GoGPT Best VPN GoSearch

Biểu tượng yêu thích OnWorks

ns-3-manual - Trực tuyến trên đám mây

Chạy ns-3-manual trong nhà cung cấp dịch vụ lưu trữ miễn phí OnWorks trên Ubuntu Online, Fedora Online, trình mô phỏng trực tuyến Windows hoặc trình mô phỏng trực tuyến MAC OS

Đây là lệnh ns-3-manual có thể chạy trong nhà cung cấp dịch vụ lưu trữ miễn phí OnWorks bằng cách sử dụng một trong nhiều máy trạm trực tuyến miễn phí của chúng tôi như Ubuntu Online, Fedora Online, trình mô phỏng trực tuyến Windows hoặc trình mô phỏng trực tuyến MAC OS

CHƯƠNG TRÌNH:

TÊN


ns-3-manual - hướng dẫn ns-3

Đây là ns-3 Hướng dẫn sử dụng. Tài liệu chính cho dự án ns-3 có sẵn trong năm
các hình thức:

· ns-3 doxygen: Tài liệu về các API công khai của trình mô phỏng

· Hướng dẫn, hướng dẫn sử dụng (điều này tài liệu)và Thư viện mẫu cho mới nhất phát hành
phát triển cây

· ns-3 wiki

NỘI DUNG


Cơ quan
Chương này mô tả tổng thể ns-3 tổ chức phần mềm và các công việc tương ứng
việc tổ chức cuốn sách hướng dẫn này.

ns-3 là một trình mô phỏng mạng sự kiện rời rạc trong đó lõi mô phỏng và các mô hình được
được thực hiện trong C++. ns-3 được xây dựng như một thư viện có thể tĩnh hoặc động
được liên kết với chương trình chính C++ xác định cấu trúc liên kết mô phỏng và bắt đầu
giả lập. ns-3 cũng xuất gần như toàn bộ API của nó sang Python, cho phép các chương trình Python
nhập mô-đun "ns3" theo cách tương tự như ns-3 thư viện được liên kết bởi các tệp thực thi
trong C ++.
[hình ảnh] Tổ chức phần mềm của ns-3.UNINDENT

Mã nguồn cho ns-3 chủ yếu được tổ chức ở src thư mục và có thể được mô tả
bằng sơ đồ ở Phần mềm cơ quan of ns-3. Chúng tôi sẽ làm việc theo cách của chúng tôi từ dưới lên
hướng lên; nói chung, các mô-đun chỉ có sự phụ thuộc vào các mô-đun bên dưới chúng trong hình.

Đầu tiên chúng tôi mô tả cốt lõi của trình mô phỏng; những thành phần phổ biến trên tất cả
các mô hình giao thức, phần cứng và môi trường. Lõi mô phỏng được thực hiện trong
src / core. Các gói là các đối tượng cơ bản trong trình mô phỏng mạng và được triển khai trong
src / mạng. Bản thân hai mô-đun mô phỏng này nhằm mục đích bao gồm một
lõi mô phỏng chung có thể được sử dụng bởi các loại mạng khác nhau, không chỉ
Mạng dựa trên Internet. Các module trên của ns-3 độc lập với mạng cụ thể
và các mẫu thiết bị được đề cập trong các phần tiếp theo của sách hướng dẫn này.

Ngoài việc nêu trên ns-3 cốt lõi, chúng tôi cũng giới thiệu trong phần đầu tiên của
manual, hai mô-đun khác bổ sung cho API cốt lõi dựa trên C++. ns-3 chương trình có thể
truy cập trực tiếp vào tất cả API hoặc có thể sử dụng cái gọi là helper API cung cấp
các trình bao bọc tiện lợi hoặc đóng gói các lệnh gọi API cấp thấp. Sự thật là ns-3 chương trình
có thể được ghi vào hai API (hoặc sự kết hợp của chúng) là một khía cạnh cơ bản của
giả lập. Chúng tôi cũng mô tả cách Python được hỗ trợ trong ns-3 trước khi chuyển sang cụ thể
các mô hình liên quan đến mô phỏng mạng.

Phần còn lại của sổ tay tập trung vào việc ghi lại các mô hình và hỗ trợ
khả năng. Phần tiếp theo tập trung vào hai đối tượng cơ bản trong ns-3: Các Node
thiết bị mạng. Hai loại NetDevice đặc biệt được thiết kế để hỗ trợ sử dụng mô phỏng mạng
trường hợp, và mô phỏng được mô tả tiếp theo. Chương sau đây được dành cho
Các mô hình liên quan đến Internet, bao gồm API ổ cắm được các ứng dụng Internet sử dụng. Các
chương tiếp theo đề cập đến các ứng dụng và chương sau mô tả hỗ trợ bổ sung
để mô phỏng, chẳng hạn như hoạt hình và thống kê.

Dự án duy trì một sổ tay riêng biệt dành cho việc thử nghiệm và xác nhận các ns-3
(Xem ns-3 Kiểm tra THẨM ĐỊNH nhãn hiệu).

ngẫu nhiên Biến
ns-3 chứa bộ tạo số giả ngẫu nhiên tích hợp (PRNG). Nó quan trọng đối với
người dùng nghiêm túc của trình mô phỏng để hiểu chức năng, cấu hình và cách sử dụng
của PRNG này và quyết định xem liệu nó có đủ cho mục đích nghiên cứu của mình hay không.

Nhanh chóng Giới thiệu chung
ns-3 số ngẫu nhiên được cung cấp thông qua các trường hợp ns3::RandomVariableStream.

· theo mặc định, ns-3 mô phỏng sử dụng một hạt giống cố định; nếu có bất kỳ sự ngẫu nhiên nào trong
mô phỏng, mỗi lần chạy chương trình sẽ mang lại kết quả giống nhau trừ khi hạt giống và/hoặc
số chạy được thay đổi.

· TRONG ns-3.3 và trước đó, ns-3 mô phỏng sử dụng hạt giống ngẫu nhiên theo mặc định; điều này đánh dấu một
thay đổi chính sách bắt đầu từ ns-3.4.

· TRONG ns-3.14 và trước đó, ns-3 mô phỏng đã sử dụng một lớp bao bọc khác gọi là
ns3::Biến ngẫu nhiên. Kể từ ns-3.15, lớp này đã được thay thế bởi
ns3::RandomVariableStream; trình tạo số giả ngẫu nhiên cơ bản chưa
đã thay đổi

· để đạt được tính ngẫu nhiên qua nhiều lần chạy mô phỏng, bạn phải đặt hạt giống
khác nhau hoặc đặt số lần chạy khác nhau. Để đặt hạt giống, hãy gọi
ns3::RngSeedManager::SetSeed() vào đầu chương trình; để thiết lập số lần chạy với
cùng một hạt giống, gọi ns3::RngSeedManager::SetRun() vào đầu chương trình; nhìn thấy
Tạo ngẫu nhiên biến.

· mỗi RandomVariableStream được sử dụng trong ns-3 có một trình tạo số ngẫu nhiên ảo được liên kết
với nó; tất cả các biến ngẫu nhiên sử dụng hạt giống cố định hoặc ngẫu nhiên dựa trên việc sử dụng
hạt giống toàn cầu (dấu đầu dòng trước);

· nếu bạn dự định thực hiện nhiều lần chạy cùng một kịch bản, với các ngẫu nhiên khác nhau
số, hãy nhớ đọc phần về cách thực hiện sao chép độc lập:
Tạo ngẫu nhiên biến.

Đọc thêm để được giải thích thêm về cơ sở số ngẫu nhiên cho ns-3.

Tiểu sử
Mô phỏng sử dụng nhiều số ngẫu nhiên; một nghiên cứu cho thấy hầu hết các mô phỏng mạng
dành tới 50% CPU để tạo ra các số ngẫu nhiên. Người dùng mô phỏng cần phải
quan tâm đến chất lượng của các số ngẫu nhiên (giả) và sự độc lập giữa
các dòng số ngẫu nhiên khác nhau.

Người dùng cần quan tâm đến một số vấn đề như:

· gieo mầm trình tạo số ngẫu nhiên và liệu kết quả mô phỏng có đúng hay không
xác định hay không,

· cách thu được các dòng số ngẫu nhiên khác nhau độc lập với một
cái khác, và

· Mất bao lâu để các luồng quay vòng

Chúng tôi sẽ giới thiệu một số thuật ngữ ở đây: RNG cung cấp một chuỗi dài các thông tin ngẫu nhiên (giả)
những con số. Độ dài của chuỗi này được gọi là chu kỳ chiều dài or thời gian, sau đó
RNG sẽ tự lặp lại. Trình tự này có thể được phân chia thành rời rạc dòng. Một
Luồng RNG là tập hợp con hoặc khối liền kề của chuỗi RNG. Ví dụ, nếu
Khoảng thời gian RNG có độ dài N và hai luồng được cung cấp từ RNG này, sau đó là luồng đầu tiên
luồng có thể sử dụng giá trị N/2 đầu tiên và luồng thứ hai có thể tạo ra N/2 thứ hai
các giá trị. Một đặc tính quan trọng ở đây là hai luồng không tương quan với nhau. Tương tự như vậy,
mỗi luồng có thể được phân chia rời rạc thành một số luồng không tương quan dòng phụ. Các
RNG cơ bản hy vọng tạo ra một chuỗi số giả ngẫu nhiên với thời gian rất dài
độ dài chu kỳ và phân chia luồng này thành luồng và luồng con một cách hiệu quả.

ns-3 sử dụng cùng một trình tạo số ngẫu nhiên cơ bản như ns-2: MRG32k3a
máy phát điện của Pierre L'Ecuyer. Một mô tả chi tiết có thể được tìm thấy trong
http://www.iro.umontreal.ca/~lecuyer/myftp/papers/streams00.pdf. Máy phát điện MRG32k3a
cung cấp 1.8x10^{19} luồng số ngẫu nhiên độc lập, mỗi luồng bao gồm
luồng con 2.3x10^{15}. Mỗi dòng con có một khoảng thời gian (tức là, số lượng các số ngẫu nhiên
trước khi chồng chéo) là 7.6x10^{22}. Chu kỳ của toàn bộ máy phát điện là 3.1x10^{57}.

Lớp ns3::RandomVariableStream là giao diện chung cho số ngẫu nhiên cơ bản này
máy phát điện. Khi người dùng tạo các biến ngẫu nhiên mới (chẳng hạn như ns3::Đồng phụcRandomBiến,
ns3::ExexponentialRandomVariable, v.v.), họ tạo ra một đối tượng sử dụng một trong các
các luồng riêng biệt, độc lập của bộ tạo số ngẫu nhiên. Vì vậy, mỗi đối tượng của
kiểu ns3::RandomVariableStream về mặt khái niệm có RNG "ảo" của riêng nó. Hơn nữa,
mỗi ns3::RandomVariableStream có thể được cấu hình để sử dụng một trong các tập hợp các luồng con được rút ra
từ luồng chính.

Một cách triển khai thay thế sẽ là cho phép mỗi RandomVariable có cái riêng của nó
(hạt giống khác nhau) RNG. Tuy nhiên, chúng tôi không thể đảm bảo chắc chắn rằng sự khác biệt
trình tự sẽ không tương quan trong trường hợp như vậy; do đó, chúng tôi thích sử dụng một RNG duy nhất và
luồng và luồng con từ nó.

Tạo ngẫu nhiên biến
ns-3 hỗ trợ một số đối tượng biến ngẫu nhiên từ lớp cơ sở
Dòng biến ngẫu nhiên. Các đối tượng này xuất phát từ ns3 :: Đối tượng và được xử lý thông minh
con trỏ.

Cách chính xác để tạo các đối tượng này là sử dụng khuôn mẫu Tạo đối tượng<> phương pháp,
chẳng hạn như:

Ptr x = CreateObject ();

sau đó bạn có thể truy cập các giá trị bằng cách gọi các phương thức trên đối tượng, chẳng hạn như:

myRandomNo = x->GetInteger ();

Thay vào đó, nếu bạn cố gắng làm một cái gì đó như thế này:

myRandomNo = Đồng phụcRandomVariable().GetInteger ();

chương trình của bạn sẽ gặp phải lỗi phân đoạn vì việc triển khai phụ thuộc vào
một số cấu trúc thuộc tính chỉ xảy ra khi Tạo đối tượng được gọi là.

Phần lớn phần còn lại của chương này thảo luận về các tính chất của dòng
các số giả ngẫu nhiên được tạo ra từ các đối tượng đó và cách kiểm soát việc gieo mầm các số đó
các đối tượng.

Gieo hạt độc lập nhân rộng
ns-3 mô phỏng có thể được cấu hình để tạo ra kết quả xác định hoặc ngẫu nhiên. Nếu
ns-3 mô phỏng được cấu hình để sử dụng một hạt giống xác định, cố định có cùng số lần chạy,
nó sẽ cho cùng một đầu ra mỗi lần chạy.

Theo mặc định, ns-3 mô phỏng sử dụng số hạt giống và số lần chạy cố định. Các giá trị này được lưu trữ trong
hai ns3::GlobalValue các trường hợp: g_rngSeedg_rngRun.

Một trường hợp sử dụng điển hình là chạy mô phỏng như một chuỗi các thử nghiệm độc lập, để
tính toán số liệu thống kê trên một số lượng lớn các lần chạy độc lập. Người dùng có thể thay đổi
hạt giống toàn cầu và chạy lại mô phỏng hoặc có thể nâng cao trạng thái dòng phụ của RNG, trạng thái này
được gọi là tăng số lần chạy.

Một lớp học ns3::RngSeedManager cung cấp API để kiểm soát số lần gieo và chạy
hành vi. Cài đặt trạng thái gieo hạt và dòng phụ này phải được gọi trước bất kỳ
các biến được tạo ra; ví dụ:

RngSeedManager::SetSeed (3); // Thay đổi hạt giống từ mặc định 1 thành 3
RngSeedManager::SetRun (7); // Thay đổi số lần chạy từ mặc định từ 1 thành 7
// Bây giờ, tạo các biến ngẫu nhiên
Ptr x = CreateObject ();
Ptr y = CreateObject ();
...

Cái nào tốt hơn, thiết lập hạt giống mới hay nâng cao trạng thái phụ? Không có
đảm bảo rằng các luồng do hai hạt ngẫu nhiên tạo ra sẽ không chồng lên nhau. Cách duy nhất để
đảm bảo rằng hai luồng không trùng nhau là sử dụng khả năng luồng con được cung cấp bởi
việc triển khai RNG. Vì vậy, sử dụng các dòng phụ khả năng đến sản xuất nhiều
độc lập chạy of các tương tự mô phỏng. Nói cách khác, càng chặt chẽ về mặt thống kê
Cách để định cấu hình nhiều bản sao độc lập là sử dụng hạt giống cố định và nâng cao
số chạy. Việc triển khai này cho phép tối đa 2.3x10^{15} độc lập
sao chép bằng cách sử dụng các dòng con.

Để dễ sử dụng, không cần thiết phải kiểm soát hạt giống và số lần chạy từ bên trong
chương trình; người dùng có thể thiết lập NS_GLOBAL_VALUE biến môi trường như sau:

$ NS_GLOBAL_VALUE="RngRun=3" ./waf --run tên chương trình

Một cách khác để kiểm soát điều này là truyền đối số dòng lệnh; vì đây là một ns-3
GlobalValue, nó được thực hiện tương đương như sau:

$ ./waf --command-template="%s --RngRun=3" --run tên chương trình

hoặc nếu bạn đang chạy các chương trình trực tiếp bên ngoài waf:

$ ./build/optimized/scratch/program-name --RngRun=3

Các biến thể dòng lệnh trên giúp bạn dễ dàng chạy nhiều lần chạy khác nhau từ một trình bao
tập lệnh bằng cách chuyển một chỉ mục RngRun khác.

Lớp Dòng biến ngẫu nhiên
Tất cả các biến ngẫu nhiên phải xuất phát từ lớp Biến ngẫu nhiên. Lớp cơ sở này cung cấp một
một số phương pháp để cấu hình toàn cầu hoạt động của bộ tạo số ngẫu nhiên. Nguồn gốc
các lớp cung cấp API để vẽ các biến ngẫu nhiên từ phân phối cụ thể
được hỗ trợ.

Mỗi RandomVariableStream được tạo trong mô phỏng được cung cấp một trình tạo mới
RNGStream từ PRNG cơ bản. Được sử dụng theo cách này, việc triển khai L'Ecuyer
cho phép tối đa 1.8x10^19 biến ngẫu nhiên. Mỗi biến ngẫu nhiên trong một
sao chép có thể tạo ra tối đa 7.6x10^22 số ngẫu nhiên trước khi chồng chéo.

Căn cứ tốt nghiệp lớp XNUMX công khai API
Dưới đây được trích dẫn một vài phương thức công khai của lớp Dòng biến ngẫu nhiên truy cập vào
giá trị tiếp theo trong dòng con.

/ **
* \brief Trả về một giá trị gấp đôi ngẫu nhiên từ phân phối cơ bản
* \return Một giá trị ngẫu nhiên dấu phẩy động
*/
nhân đôi GetValue (void) const;

/ **
* \brief Trả về một số nguyên ngẫu nhiên từ phân phối cơ bản
* \return Truyền số nguyên của ::GetValue()
*/
uint32_t GetInteger (void) const;

Chúng tôi đã mô tả cấu hình gieo hạt ở trên. Biến ngẫu nhiên khác nhau
các lớp con có thể có API bổ sung.

Các loại of Biến ngẫu nhiên
Các loại biến ngẫu nhiên sau đây được cung cấp và được ghi lại trong ns-3
Doxygen hoặc bằng cách đọc src/core/model/random-variable-stream.h. Người dùng cũng có thể tạo
các biến ngẫu nhiên tùy chỉnh của riêng họ bằng cách lấy từ lớp Dòng biến ngẫu nhiên.

· lớp Thống nhấtNgẫu nhiênBiến

· lớp Hằng sốNgẫu nhiênBiến

· lớp Tuần tựNgẫu nhiênBiến

· lớp Hàm mũNgẫu nhiênBiến

· lớp ParetoNgẫu nhiênBiến

· lớp WeibullNgẫu nhiênBiến

· lớp Bình thườngNgẫu nhiênBiến

· lớp Đăng nhậpBình thườngNgẫu nhiênBiến

· lớp Gamma Biến ngẫu nhiên

· lớp ErlangNgẫu nhiênBiến

· lớp Tam giácNgẫu nhiênBiến

· lớp ZipfNgẫu nhiênBiến

· lớp ZetaBiến ngẫu nhiên

· lớp Tất địnhNgẫu nhiênBiến

· lớp Thực nghiệmNgẫu nhiênBiến

Ngữ nghĩa of Dòng biến ngẫu nhiên đối tượng
Các đối tượng RandomVariableStream xuất phát từ ns3 :: Đối tượng và được xử lý bởi con trỏ thông minh.

Các phiên bản RandomVariableStream cũng có thể được sử dụng trong ns-3 thuộc tính, có nghĩa là
các giá trị có thể được đặt cho chúng thông qua ns-3 hệ thống thuộc tính. Một ví dụ là trong
mô hình lan truyền cho WifiNetDevice:

loạiId
RandomPropagationDelayModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel")
.SetParent ()
.AddConstructor ()
.AddAttribution ("Biến",
"Biến ngẫu nhiên tạo ra (các) độ trễ ngẫu nhiên",
StringValue ("ns3::UniformRandomVariable"),
MakePointerAccessor (&RandomPropagationDelayModel::m_variable),
MakePointerChecker ())
;
trả lại tid;
}

Ở đây, ns-3 người dùng có thể thay đổi biến ngẫu nhiên mặc định cho mô hình độ trễ này (đó là
một biến thống nhất ngẫu nhiên có phạm vi từ 0 đến 1) thông qua hệ thống thuộc tính.

Sử dụng Khác PRNG
Hiện tại không có hỗ trợ nào cho việc thay thế một số ngẫu nhiên cơ bản khác
trình tạo (ví dụ: Thư viện khoa học GNU hoặc gói Akaroa). Các bản vá được chào đón.

Giàn cảnh các dòng con số
Trình tạo MRG32k3a cơ bản cung cấp 2^64 luồng độc lập. Trong ns-3, đây là
được chỉ định tuần tự bắt đầu từ luồng đầu tiên dưới dạng phiên bản RandomVariableStream mới
thực hiện cuộc gọi đầu tiên tới GetValue().

Do cách các đối tượng RandomVariableStream này được gán cho các luồng cơ bản,
bài tập rất nhạy cảm với sự nhiễu loạn của cấu hình mô phỏng. Các
hậu quả là nếu bất kỳ khía cạnh nào của cấu hình mô phỏng bị thay đổi, ánh xạ
của RandomVariables vào luồng có thể (hoặc có thể không) thay đổi.

Một ví dụ cụ thể, người dùng đang thực hiện nghiên cứu so sánh giữa các giao thức định tuyến có thể
thấy rằng hành động thay đổi giao thức định tuyến này sang giao thức định tuyến khác sẽ nhận thấy rằng
mô hình di chuyển cơ bản cũng thay đổi.

Bắt đầu với ns-3.15, một số điều khiển đã được cung cấp cho người dùng để cho phép người dùng
tùy ý sửa việc gán các đối tượng RandomVariableStream đã chọn thành cơ bản
dòng suối. Đây là Sông thuộc tính, một phần của lớp cơ sở RandomVariableStream.

Bằng cách phân vùng chuỗi luồng hiện có từ trước:

<------------------------------------------------- -------------------------->
luồng 0 luồng (2^64 - 1)

thành hai tập hợp có kích thước bằng nhau:

<------------------------------------------------- -------------------------->
^ ^^ ^
| || |
luồng 0 luồng (2^63 - 1) luồng 2^63 luồng (2^64 - 1)
<- được gán tự động ----------><- do người dùng gán ------------------>

2^63 luồng đầu tiên tiếp tục được gán tự động, trong khi 2^63 luồng cuối cùng được
chỉ số luồng đã cho bắt đầu bằng 2 cho đến 63^1-XNUMX.

Việc gán các luồng cho một số luồng cố định là tùy chọn; Trường hợp của
RandomVariableStream không được chỉ định giá trị luồng sẽ được chỉ định ở lần tiếp theo
một từ nhóm luồng tự động.

Để sửa RandomVariableStream thành một luồng cơ bản cụ thể, hãy gán nó Sông
thuộc tính thành một số nguyên không âm (giá trị mặc định là -1 có nghĩa là một giá trị sẽ là
được phân bổ tự động).

Xuất bản qua một vài thao tác đơn giản về các kết quả
Khi bạn công bố kết quả mô phỏng, một phần quan trọng của thông tin cấu hình mà bạn
phải luôn nêu rõ cách bạn sử dụng trình tạo số ngẫu nhiên.

· bạn đã sử dụng hạt giống gì,

· RNG nào bạn đã sử dụng nếu không phải là mặc định,

· Các hoạt động độc lập được thực hiện như thế nào,

· đối với các mô phỏng lớn, làm thế nào bạn kiểm tra được rằng bạn không quay vòng.

Nhiệm vụ của nhà nghiên cứu là công bố kết quả phải bao gồm đủ thông tin để
cho phép người khác sao chép kết quả của mình. Người nghiên cứu cũng có nhiệm vụ
thuyết phục bản thân rằng các số ngẫu nhiên được sử dụng có giá trị về mặt thống kê và nêu rõ
bài báo tại sao sự tự tin như vậy được giả định.

Tổng kết
Hãy xem lại những điều bạn nên làm khi tạo mô phỏng.

· Quyết định xem bạn đang chạy với hạt giống cố định hay hạt giống ngẫu nhiên; một hạt giống cố định là
vỡ nợ,

· Quyết định cách bạn sẽ quản lý các bản sao độc lập, nếu có,

· Hãy thuyết phục bản thân rằng bạn không vẽ nhiều giá trị ngẫu nhiên hơn độ dài chu kỳ, nếu
bạn đang chạy một mô phỏng rất dài và

· Khi bạn xuất bản, hãy làm theo các hướng dẫn ở trên về việc ghi lại việc bạn sử dụng ngẫu nhiên
bộ tạo số.

Băm Chức năng
ns-3 cung cấp một giao diện chung cho các hàm băm có mục đích chung. Một cách đơn giản nhất
Khi sử dụng, hàm băm trả về hàm băm 32 bit hoặc 64 bit của bộ đệm hoặc chuỗi dữ liệu.
Hàm băm cơ bản mặc định là thì thầm3, được chọn vì nó có hàm băm tốt
Properties và cung cấp phiên bản 64-bit. Người đáng kính FNV1a hàm băm cũng có sẵn.

Có một cơ chế đơn giản để thêm (hoặc cung cấp trong thời gian chạy) hàm băm thay thế
việc triển khai chức năng.

Cơ bản Sử dụng
Cách đơn giản nhất để lấy giá trị băm của bộ đệm dữ liệu hoặc chuỗi chỉ là:

#include "ns3/hash.h"

sử dụng không gian tên ns3;

char * bộ đệm = ...
size_t đệm_size = ...

uint32_t buffer_hash = Hash32 ( đệm, buffer_size);

std::string s;
uint32_t string_hash = Hash32 (s);

Các hàm tương đương được xác định cho các giá trị băm 64 bit.

Tăng dần Băm
Trong một số trường hợp, việc tính toán hàm băm của nhiều bộ đệm sẽ rất hữu ích, như thể chúng có
được nối lại với nhau. (Ví dụ: bạn có thể muốn hàm băm của luồng gói, nhưng không
muốn tập hợp một bộ đệm duy nhất với nội dung kết hợp của tất cả các gói.)

Điều này gần như đơn giản như ví dụ đầu tiên:

#include "ns3/hash.h"

sử dụng không gian tên ns3;

bộ đệm char *;
size_t đệm_size;

Máy băm băm; // Sử dụng hàm băm mặc định

vì ( )
{
đệm = get_next_buffer ();
hàm băm (bộ đệm, buffer_size);
}
uint32_t kết hợp_hash = hasher.GetHash32 ();

Theo mặc định máy băm duy trì trạng thái bên trong để cho phép băm tăng dần. Nếu bạn muốn
tái sử dụng một máy băm đối tượng (ví dụ vì nó được định cấu hình bằng hàm băm không mặc định
chức năng), nhưng không muốn thêm vào hàm băm được tính toán trước đó, bạn cần phải thông thoáng()
Đầu tiên:

hasher.clear ().GetHash32 (bộ đệm, buffer_size);

Điều này khởi tạo lại trạng thái bên trong trước khi băm bộ đệm.

Sử dụng an Thay thế Băm Chức năng
Hàm băm mặc định là thì thầm3. FNV1a cũng có sẵn. Để chỉ định hàm băm
hoạt động một cách rõ ràng, hãy sử dụng bộ điều khiển này:

Máy băm băm = Máy băm ( Tạo () );

Thêm Mới Băm Chức năng Triển khai
Để thêm hàm băm foo, theo băm-murmur3.h/. Cc mẫu:

· Tạo một khai báo lớp (.h) và định nghĩa (. Cc) kế thừa từ
Băm::Thực hiện.

· bao gồm tuyên bố trong băm.h (tại thời điểm băm-murmur3.h được bao gồm.

· Trong mã của riêng bạn, khởi tạo một máy băm đối tượng thông qua hàm tạo máy băm
(Ptr ())

Nếu hàm băm của bạn là một hàm duy nhất, ví dụ: hàm băm, bạn thậm chí không cần phải tạo
lớp mới bắt nguồn từ HashImplementation:

Máy băm băm =
Máy băm ( Tạo (&hashf) );

Để biên dịch cái này, bạn hàm băm phải khớp với một trong các chữ ký của con trỏ hàm:

typedef uint32_t (*Hash32Function_ptr) (const char *, const size_t);
typedef uint64_t (*Hash64Function_ptr) (const char *, const size_t);

nguồn cho Băm Chức năng
Các nguồn để triển khai hàm băm khác bao gồm:

· Peter Kankowski: http://www.strchr.com

· Phần Arash: http://www.partow.net/programming/hashfunctions/index.html

· SMHasher: http://code.google.com/p/smhasher/

· Sanmayce: http://www.sanmayce.com/Fastest_Hash/index.html

Sự kiện Simulator
ns-3 là một trình mô phỏng mạng sự kiện rời rạc. Về mặt khái niệm, trình mô phỏng theo dõi một
số sự kiện được lên kế hoạch để thực hiện tại một thời điểm mô phỏng cụ thể. Công việc của
trình mô phỏng là thực hiện các sự kiện theo thứ tự thời gian tuần tự. Sau khi hoàn thành
một sự kiện xảy ra, trình mô phỏng sẽ chuyển sang sự kiện tiếp theo (hoặc sẽ thoát nếu không có
nhiều sự kiện hơn trong hàng đợi sự kiện). Ví dụ: nếu một sự kiện được lên lịch cho thời gian mô phỏng
"100 giây" được thực thi và sự kiện tiếp theo không được lên lịch cho đến "200 giây",
trình mô phỏng sẽ ngay lập tức nhảy từ 100 giây lên 200 giây (trong thời gian mô phỏng) tới
thực hiện sự kiện tiếp theo. Đây chính là ý nghĩa của trình mô phỏng "sự kiện rời rạc".

Để thực hiện tất cả điều này, trình mô phỏng cần một số thứ:

1. một đối tượng mô phỏng có thể truy cập hàng đợi sự kiện nơi các sự kiện được lưu trữ và có thể
quản lý việc thực hiện các sự kiện

2. người lập lịch chịu trách nhiệm chèn và xóa các sự kiện khỏi hàng đợi

3. cách biểu diễn thời gian mô phỏng

4. bản thân các sự kiện

Chương này của sổ tay mô tả các đối tượng cơ bản này (bộ mô phỏng, bộ lập lịch,
thời gian, sự kiện) và cách chúng được sử dụng.

Sự kiện
Đến be hoàn thành

Simulator
Lớp Trình mô phỏng là điểm truy cập công khai để truy cập các cơ sở lập kế hoạch sự kiện. Một lần
một vài sự kiện đã được lên lịch để bắt đầu mô phỏng, người dùng có thể bắt đầu
thực thi chúng bằng cách vào vòng lặp chính của trình mô phỏng (gọi Trình mô phỏng :: Chạy). Khi vòng lặp chính
bắt đầu chạy, nó sẽ thực hiện tuần tự tất cả các sự kiện đã lên lịch theo thứ tự từ cũ nhất đến
gần đây nhất cho đến khi không còn sự kiện nào trong hàng đợi sự kiện hoặc
Trình mô phỏng::Dừng đã được gọi.

Để lên lịch các sự kiện để thực thi bằng vòng lặp chính của trình mô phỏng, lớp Trình mô phỏng cung cấp
Nhóm chức năng Simulator::Schedule*.

1. Xử lý các trình xử lý sự kiện có chữ ký khác nhau

Các hàm này được khai báo và triển khai dưới dạng mẫu C++ để xử lý tự động các
nhiều chữ ký xử lý sự kiện C++ được sử dụng rộng rãi. Ví dụ, để lên lịch một
sự kiện để thực thi 10 giây trong tương lai và gọi một phương thức hoặc hàm C++ với
đối số cụ thể, bạn có thể viết điều này:

trình xử lý void (int arg0, int arg1)
{
std::cout << "trình xử lý được gọi với đối số arg0=" << arg0 << " và
arg1=" << arg1 << std::endl;
}

Trình mô phỏng::Lịch trình(Giây(10), &người xử lý, 10, 5);

Cái nào sẽ xuất ra:

trình xử lý được gọi với đối số arg0=10 và arg1=5

Tất nhiên, các mẫu C++ này cũng có thể xử lý các phương thức thành viên trong suốt trên C++
các đối tượng:

Đến be hoàn thành: hội viên phương pháp ví dụ

Ghi chú:

· Các phương thức Lịch trình ns-3 chỉ tự động nhận dạng các hàm và phương thức nếu chúng
lấy ít hơn 5 đối số. Nếu bạn cần chúng để hỗ trợ thêm lập luận, vui lòng gửi một
báo cáo lỗi.

· Những độc giả quen với thuật ngữ 'hàm số giới hạn đầy đủ' sẽ nhận ra
Trình mô phỏng::Lập lịch các phương thức như một cách để tự động xây dựng các đối tượng đó.

2. Thao tác lập lịch chung

API Trình mô phỏng được thiết kế để giúp việc lên lịch hầu hết các sự kiện trở nên thực sự đơn giản. Nó
cung cấp ba biến thể để làm như vậy (được sắp xếp theo thứ tự từ được sử dụng phổ biến nhất đến ít được sử dụng phổ biến nhất):

· Lên lịch các phương pháp cho phép bạn lên lịch một sự kiện trong tương lai bằng cách cung cấp
độ trễ giữa thời gian mô phỏng hiện tại và ngày hết hạn của sự kiện mục tiêu.

· Phương pháp ScheduleNow cho phép bạn lên lịch một sự kiện cho mô phỏng hiện tại
thời gian: họ sẽ thực hiện _after_ sự kiện hiện tại được thực hiện xong nhưng _trước_ sự kiện
thời gian mô phỏng được thay đổi cho sự kiện tiếp theo.

· Phương pháp ScheduleDestroy cho phép bạn kết nối quá trình tắt máy của Trình mô phỏng
để dọn sạch tài nguyên mô phỏng: mọi sự kiện 'hủy' được thực thi khi người dùng gọi
phương thức Simulator::Destroy.

3. Duy trì bối cảnh mô phỏng

Có hai cách cơ bản để lên lịch sự kiện, có và không có bối cảnh. Cái này làm gì
nghĩa là gì?

Trình mô phỏng::Lịch trình (Thời gian const &time, MEM mem_ptr, OBJ obj);

vs.

Trình mô phỏng::ScheduleWithContext (bối cảnh uint32_t, Thời gian const &time, MEM mem_ptr, OBJ obj);

Độc giả đầu tư thời gian và công sức vào việc phát triển hoặc sử dụng mô hình mô phỏng không tầm thường
sẽ biết giá trị của khung ghi nhật ký ns-3 để gỡ lỗi các mô phỏng đơn giản và phức tạp
như nhau. Một trong những tính năng quan trọng được cung cấp bởi khung ghi nhật ký này là
tự động hiển thị id nút mạng được liên kết với sự kiện đang chạy 'hiện tại'.

Trên thực tế, id nút của nút mạng hiện đang thực thi được theo dõi bởi Trình mô phỏng
lớp học. Nó có thể được truy cập bằng phương thức Simulator::GetContext trả về
'ngữ cảnh' (số nguyên 32 bit) được liên kết và lưu trữ trong sự kiện hiện đang thực thi. TRONG
một số trường hợp hiếm hoi, khi một sự kiện không được liên kết với một nút mạng cụ thể,
'ngữ cảnh' được đặt thành 0xffffffff.

Để liên kết một bối cảnh với từng sự kiện, các phương thức Schedule và ScheduleNow sẽ tự động được liên kết
tái sử dụng bối cảnh của sự kiện hiện đang thực hiện làm bối cảnh của sự kiện đã lên lịch
để thực hiện sau này.

Trong một số trường hợp, đáng chú ý nhất là khi mô phỏng việc truyền gói tin từ nút này sang nút khác.
khác, hành vi này là không mong muốn vì bối cảnh dự kiến ​​của sự kiện tiếp nhận là
của nút nhận chứ không phải nút gửi. Để tránh vấn đề này, Trình mô phỏng
lớp cung cấp một phương thức lịch trình cụ thể: ScheduleWithContext cho phép một người cung cấp
rõ ràng id nút của nút nhận được liên kết với sự kiện nhận.

XXX: ví dụ

Trong một số trường hợp rất hiếm, nhà phát triển có thể cần sửa đổi hoặc hiểu bối cảnh
(id nút) của sự kiện đầu tiên được đặt thành nút liên kết của nó. Điều này đã được thực hiện
bởi lớp NodeList: bất cứ khi nào một nút mới được tạo, lớp NodeList sẽ sử dụng
ScheduleWithContext để lên lịch sự kiện 'khởi tạo' cho nút này. Sự kiện 'khởi tạo'
do đó thực thi với ngữ cảnh được đặt thành ngữ cảnh của id nút và có thể sử dụng nhiều loại thông thường
Phương pháp lập kế hoạch. Nó gọi phương thức Node::Initialize để truyền bá 'khởi tạo'
sự kiện bằng cách gọi phương thức DoInitialize cho từng đối tượng được liên kết với nút. Các
Phương thức DoInitialize bị ghi đè trong một số đối tượng này (đáng chú ý nhất là trong Ứng dụng
lớp cơ sở) sẽ lên lịch một số sự kiện (đáng chú ý nhất là Application::StartApplication)
sẽ lần lượt lên lịch cho các sự kiện tạo lưu lượng truy cập, từ đó sẽ lên lịch
sự kiện cấp mạng.

Ghi chú:

· Người dùng cần cẩn thận khi truyền bá các phương thức DoInitialize trên các đối tượng bằng cách gọi
Khởi tạo rõ ràng trên các đối tượng thành viên của họ

· Id ngữ cảnh được liên kết với mỗi phương thức ScheduleWithContext còn có những cách sử dụng khác
ghi nhật ký: nó được sử dụng bởi nhánh thử nghiệm của ns-3 để thực hiện mô phỏng song song trên
hệ thống đa lõi sử dụng đa luồng.

Các hàm Simulator::* không biết ngữ cảnh là gì: chúng chỉ đảm bảo rằng
bất kỳ bối cảnh nào bạn chỉ định với ScheduleWithContext đều khả dụng khi bối cảnh tương ứng
sự kiện thực thi với ::GetContext.

Việc diễn giải giá trị ngữ cảnh tùy thuộc vào các mô hình được triển khai trên Simulator::*.
Trong ns-3, các mô hình mạng diễn giải ngữ cảnh dưới dạng id nút của nút đó.
đã tạo ra một sự kiện. Đây là lý do tại sao việc gọi ScheduleWithContext trong
ns3::Các lớp con kênh vì chúng tôi đang tạo một sự kiện từ nút i đến nút j và chúng tôi
muốn đảm bảo rằng sự kiện sẽ chạy trên nút j có ngữ cảnh phù hợp.

Thời gian
Đến be hoàn thành

Scheduler
Đến be hoàn thành

Gọi lại
Một số người dùng mới ns-3 không quen với một thành ngữ lập trình được sử dụng rộng rãi
trong suốt mã: ns-3 gọi lại. Chương này cung cấp một số động lực về
gọi lại, hướng dẫn cách sử dụng và chi tiết về cách triển khai.

Gọi lại Động lực
Giả sử bạn có hai mô hình mô phỏng A và B và bạn muốn chúng vượt qua
thông tin giữa chúng trong quá trình mô phỏng. Một cách mà bạn có thể làm điều đó là bạn
có thể làm cho A và B hiểu biết rõ ràng về nhau để họ có thể gọi
các phương thức với nhau:

hạng A {
công khai:
void NhậnInput ( // tham số );
...
}

(trong một tệp nguồn khác :)

lớp B {
công khai:
void DoS Something (void);
...

riêng tư:
A* a_instance; // con trỏ tới điểm A
}

làm mất hiệu lực
B::DoS Something()
{
// Nói với a_instance rằng có chuyện gì đó đã xảy ra
a_instance->ReceiveInput ( // tham số);
...
}

Điều này chắc chắn có hiệu quả, nhưng nó có nhược điểm là nó phụ thuộc vào A và B.
biết về người khác tại thời điểm biên dịch (điều này khiến việc độc lập trở nên khó khăn hơn
đơn vị biên dịch trong trình mô phỏng) và không được khái quát hóa; nếu trong trường hợp sử dụng sau này,
B cần nói chuyện với một đối tượng C hoàn toàn khác thì mã nguồn của B cần phải là
đã thay đổi để thêm một c_instance và kể từ đó trở đi. Dễ dàng nhận thấy đây là một thế lực bạo lực
cơ chế giao tiếp có thể dẫn tới việc lập trình hành trình trong các mô hình.

Điều này không có nghĩa là các đối tượng không nên biết về nhau nếu có khó khăn.
sự phụ thuộc giữa chúng, nhưng thường thì mô hình có thể trở nên linh hoạt hơn nếu nó
tương tác ít bị hạn chế hơn tại thời gian biên dịch.

Đây không phải là một vấn đề trừu tượng đối với nghiên cứu mô phỏng mạng, mà đúng hơn nó là một vấn đề
nguồn gốc của các vấn đề trong các trình mô phỏng trước đó, khi các nhà nghiên cứu muốn mở rộng hoặc sửa đổi
hệ thống để làm những việc khác nhau (như họ có khả năng làm trong nghiên cứu). Hãy xem xét, ví dụ,
người dùng muốn thêm lớp con giao thức bảo mật IPsec giữa TCP và IP:

------------ ----------
| TCP | | TCP |
------------ ----------
| trở thành -> |
------------- ----------
| IP | | IPsec |
------------- ----------
|
-----------
| IP |
-----------

Nếu trình mô phỏng đã đưa ra các giả định và được mã hóa cứng vào mã thì IP đó luôn nói
với giao thức truyền tải ở trên, người dùng có thể bị buộc phải hack hệ thống để lấy được
các kết nối mong muốn. Đây rõ ràng không phải là cách tối ưu để thiết kế một hệ thống chung
giả lập.

Gọi lại Tiểu sử
LƯU Ý:
Người đọc quen với lệnh gọi lại trong lập trình có thể bỏ qua phần hướng dẫn này.

Cơ chế cơ bản cho phép giải quyết vấn đề trên được gọi là gọi lại.
Mục tiêu cuối cùng là cho phép một đoạn mã gọi một hàm (hoặc phương thức trong C++)
không có bất kỳ sự phụ thuộc giữa các mô-đun cụ thể nào.

Điều này cuối cùng có nghĩa là bạn cần một số loại gián tiếp -- bạn xử lý địa chỉ của
được gọi là hàm như một biến. Biến này được gọi là biến con trỏ tới hàm.
Mối quan hệ giữa hàm và con trỏ trỏ tới hàm thực sự không có gì khác biệt
đó là đối tượng và con trỏ tới đối tượng.

Trong C, ví dụ chính tắc về một con trỏ đến hàm là
con trỏ tới hàm trả về số nguyên (PFI). Đối với một PFI lấy một tham số int, điều này
có thể được khai báo như,:

int (* pfi) (int arg) = 0;

Những gì bạn nhận được từ đây là một biến có tên đơn giản pfi được khởi tạo ở giá trị 0.
Nếu bạn muốn khởi tạo con trỏ này thành một cái gì đó có ý nghĩa, bạn phải có một
chức năng với một chữ ký phù hợp. Trong trường hợp này:

int MyFunction (int arg) {}

Nếu bạn có mục tiêu này, bạn có thể khởi tạo biến để trỏ đến hàm của mình như:

pfi = Chức năng của tôi;

Sau đó, bạn có thể gọi MyFunction gián tiếp bằng cách sử dụng hình thức gọi gợi ý hơn:

int result = (* pfi) (1234);

Đây là gợi ý vì có vẻ như bạn đang tham khảo con trỏ hàm chỉ
giống như bạn sẽ tham khảo bất kỳ con trỏ nào. Tuy nhiên, thông thường, mọi người tận dụng lợi thế của
thực tế là trình biên dịch biết điều gì đang xảy ra và sẽ chỉ sử dụng một biểu mẫu ngắn hơn:

kết quả int = pfi (1234);

Lưu ý rằng con trỏ hàm tuân theo ngữ nghĩa giá trị, vì vậy bạn có thể chuyển nó đi khắp nơi như bất kỳ
giá trị khác. Thông thường, khi bạn sử dụng giao diện không đồng bộ, bạn sẽ chuyển một số thực thể
như thế này với một chức năng sẽ thực hiện một hành động và cuộc gọi trở lại để cho bạn biết điều đó
hoàn thành. Nó gọi lại bằng cách làm theo hướng dẫn và thực hiện chức năng được cung cấp.

Trong C++ bạn có thêm độ phức tạp của các đối tượng. Sự tương tự với PFI ở trên có nghĩa là bạn
có một con trỏ tới hàm thành viên trả về int (PMI) thay vì con trỏ tới
hàm trả về một int (PFI).

Việc khai báo biến cung cấp hướng dẫn trông chỉ hơi khác một chút:

int (MyClass::*pmi) (int arg) = 0;

Điều này khai báo một biến có tên pmi giống như ví dụ trước đã khai báo một biến có tên
pfi. Vì sẽ gọi một phương thức của một thể hiện của một lớp cụ thể, nên người ta phải
khai báo phương thức đó trong một lớp:

lớp MyClass {
công khai:
int MyMethod (int arg);
};

Với khai báo lớp này, người ta sẽ khởi tạo biến đó như sau:

pmi = &MyClass::MyMethod;

Điều này gán địa chỉ của mã thực hiện phương thức cho biến, hoàn thành
sự gián tiếp. Để gọi một phương thức, mã cần có một điều này con trỏ. Điều này, đến lượt nó,
nghĩa là phải có đối tượng MyClass để tham chiếu. Một ví dụ đơn giản về điều này chỉ là
gọi một phương thức gián tiếp (nghĩ hàm ảo):

int (MyClass::*pmi) (int arg) = 0; // Khai báo PMI
pmi = &MyClass::MyMethod; // Trỏ vào đoạn code thực thi

MyClass myClass; // Cần một thể hiện của lớp
(myClass.*pmi) (1234); // Gọi phương thức với đối tượng ptr

Giống như trong ví dụ C, bạn có thể sử dụng điều này trong lệnh gọi không đồng bộ đến mô-đun khác
cái nào sẽ cuộc gọi trở lại sử dụng một phương thức và một con trỏ đối tượng. Phần mở rộng đơn giản
người ta có thể cân nhắc việc chuyển một con trỏ tới đối tượng và biến PMI. mô-đun
sẽ chỉ làm:

(*objectPtr.*pmi) (1234);

để thực hiện cuộc gọi lại trên đối tượng mong muốn.

Người ta có thể hỏi vào lúc này, cái gì các điểm? Mô-đun được gọi sẽ phải hiểu
loại cụ thể của đối tượng gọi để thực hiện gọi lại đúng cách. Tại sao không
chỉ cần chấp nhận điều này, chuyển con trỏ đối tượng được gõ chính xác và làm đối tượng->Phương pháp(1234) in
mã thay vì gọi lại? Đây chính xác là vấn đề được mô tả ở trên. Là gì
cần thiết là một cách để tách hoàn toàn chức năng gọi khỏi lớp được gọi. Cái này
yêu cầu đã dẫn tới sự phát triển của chức năng.

Functor là sự phát triển tự nhiên của một thứ được phát minh vào những năm 1960 được gọi là bao đóng. Nó là
về cơ bản chỉ là một lệnh gọi hàm được đóng gói, có thể có một số trạng thái.

Một functor có hai phần, một phần cụ thể và một phần chung, liên quan với nhau thông qua tính kế thừa.
Mã gọi (mã thực thi lệnh gọi lại) sẽ thực thi quá tải chung
nhà điều hành () của một functor chung để gọi lại lệnh gọi lại. Mã được gọi (
mã muốn được gọi lại) sẽ phải cung cấp một triển khai chuyên biệt của
các nhà điều hành () thực hiện công việc dành riêng cho lớp gây ra sự liên kết chặt chẽ
vấn đề trên.

Với hàm cụ thể và tình trạng quá tải của nó nhà điều hành () được tạo, mã được gọi sau đó
cung cấp mã chuyên dụng cho mô-đun sẽ thực hiện lệnh gọi lại (lệnh gọi
mã số).

Mã gọi sẽ lấy một functor chung làm tham số, do đó việc truyền ẩn được thực hiện
trong lệnh gọi hàm để chuyển đổi functor cụ thể thành functor chung. Điều này có nghĩa là
rằng mô-đun gọi chỉ cần hiểu loại functor chung. Nó được tách rời
hoàn toàn khỏi mã cuộc gọi.

Thông tin cần thiết để tạo một functor cụ thể là con trỏ đối tượng và
địa chỉ con trỏ tới phương thức.

Bản chất của những gì cần xảy ra là hệ thống khai báo một phần chung của
chức năng:

bản mẫu
lớp hàm
{
công khai:
toán tử int ảo() (T arg) = 0;
};

Người gọi xác định một phần cụ thể của functor mà thực sự chỉ ở đó để triển khai
cụ thể nhà điều hành() phương pháp:

bản mẫu
lớp cụ thểFunctor : Functor công cộng
{
công khai:
Cụ thể(T* p, int (T::*_pmi)(ARG arg))
{
m_p = p;
m_pmi = _pmi;
}

toán tử int ảo() (ARG arg)
{
(*m_p.*m_pmi)(arg);
}
riêng tư:
int (T::*m_pmi)(ARG arg);
T* m_p;
};

Đây là một ví dụ về việc sử dụng:

hạng A
{
công khai:
A (int a0): a (a0) {}
int Xin chào (int b0)
{
std::cout << "Xin chào từ A, a = " << a << " b0 = " << b0 << std::endl;
}
int một;
};

int main ()
{
A a(10);
Hàm cụ thể sf(&a, &A::Xin chào);
sf(5);
}

LƯU Ý:
Mã trước đó không phải là mã ns-3 thực. Đó là mã ví dụ đơn giản chỉ được sử dụng để
minh họa các khái niệm liên quan và giúp bạn hiểu hệ thống hơn. Đừng
mong đợi tìm thấy mã này ở bất kỳ đâu trong cây ns-3.

Lưu ý rằng có hai biến được định nghĩa trong lớp trên. Biến m_p là
con trỏ đối tượng và m_pmi là biến chứa địa chỉ của hàm cần
hành hình.

Chú ý rằng khi nhà điều hành() được gọi, nó lần lượt gọi phương thức được cung cấp cùng với
con trỏ đối tượng bằng cú pháp C++ PMI.

Để sử dụng điều này, người ta có thể khai báo một số mã mô hình lấy một functor chung làm
tham số:

void LibraryFunction (Functor functor);

Đoạn mã giao tiếp với mô hình sẽ xây dựng một functor cụ thể và chuyển nó tới
Thư việnChức năng:

MyClass myClass;
Hàm cụ thể functor (&myclass, MyClass::MyMethod);

Thời Gian Thư việnChức năng hoàn tất, nó thực hiện lệnh gọi lại bằng cách sử dụng nhà điều hành() về cái chung
functor nó đã được truyền và trong trường hợp cụ thể này, nó cung cấp đối số nguyên:

làm mất hiệu lực
Hàm thư viện (Functor functor)
{
// Thực thi hàm thư viện
người điều khiển(1234);
}

Thông báo rằng Thư việnChức năng được tách hoàn toàn khỏi loại cụ thể của khách hàng.
Kết nối được thực hiện thông qua đa hình Functor.

API gọi lại trong ns-3 thực hiện các lệnh gọi lại hướng đối tượng bằng cơ chế functor.
API gọi lại này, dựa trên các mẫu C++, là loại an toàn; nghĩa là nó thực hiện tĩnh
kiểm tra loại để thực thi khả năng tương thích chữ ký phù hợp giữa người gọi và người được gọi. Nó là
do đó sử dụng an toàn hơn về kiểu so với các con trỏ hàm truyền thống, nhưng cú pháp có thể
thoạt nhìn có vẻ hoành tráng. Phần này được thiết kế để hướng dẫn bạn qua hệ thống Gọi lại
để bạn có thể thoải mái sử dụng nó trong ns-3.

Sử dụng các Gọi lại API
API gọi lại khá tối thiểu, chỉ cung cấp hai dịch vụ:

1. Khai báo kiểu gọi lại: một cách khai báo một kiểu gọi lại với chữ ký nhất định,
và,

2. khởi tạo cuộc gọi lại: một cách để khởi tạo cuộc gọi lại chuyển tiếp do mẫu tạo
có thể chuyển tiếp bất kỳ cuộc gọi nào đến một phương thức thành viên lớp C++ khác hoặc hàm C++.

Điều này được quan sát tốt nhất bằng cách xem qua một ví dụ, dựa trên mẫu/main-callback.cc.

Sử dụng các Gọi lại API với tĩnh chức năng
Hãy xem xét một chức năng:

tĩnh đôi
CbOne (nhân đôi a, nhân đôi b)
{
std::cout << "gọi cbOne a=" << a << ", b=" << b << std::endl;
trả lại một;
}

Hãy xem xét đoạn chương trình chính sau:

int main (int argc, char * argv [])
{
// kiểu trả về: gấp đôi
// kiểu đối số đầu tiên: double
// loại đối số thứ hai: double
Gọi lại một;
}

Đây là một ví dụ về lệnh gọi lại kiểu C -- một lệnh gọi lại không bao gồm hoặc cần một điều này
con trỏ. Mẫu chức năng Gọi lại về cơ bản là khai báo biến
chứa con trỏ tới hàm. Trong ví dụ trên, chúng tôi đã hiển thị rõ ràng một con trỏ
tới một hàm trả về một số nguyên và lấy một số nguyên duy nhất làm tham số, The
Gọi lại hàm mẫu là phiên bản chung của hàm đó -- nó được dùng để khai báo kiểu
của một cuộc gọi lại.

LƯU Ý:
Bạn đọc chưa quen với các mẫu C++ có thể tham khảo
http://www.cplusplus.com/doc/tutorial/templates/.

Gọi lại mẫu yêu cầu một đối số bắt buộc (kiểu trả về của hàm cho
được gán cho cuộc gọi lại này) và tối đa năm đối số tùy chọn, mỗi đối số chỉ định
loại đối số (nếu hàm gọi lại cụ thể của bạn có nhiều hơn năm đối số,
thì điều này có thể được xử lý bằng cách mở rộng triển khai gọi lại).

Vì vậy, trong ví dụ trên, chúng ta đã khai báo một lệnh gọi lại có tên là "one" mà cuối cùng sẽ
giữ một con trỏ hàm. Chữ ký của hàm mà nó sẽ giữ phải trả về
double và phải hỗ trợ hai đối số kép. Nếu người ta cố gắng truyền một hàm có
chữ ký không khớp với lệnh gọi lại đã khai báo, sẽ xảy ra lỗi biên dịch. Còn nếu
người ta cố gắng gán cho một cuộc gọi lại một cuộc gọi lại không tương thích, quá trình biên dịch sẽ thành công nhưng
thời gian chạy NS_FATAL_ERROR sẽ tăng lên. Chương trình mẫu
src/core/examples/main-callback.cc minh họa cả hai trường hợp lỗi này ở cuối
các chủ yếu() chương trình.

Bây giờ, chúng ta cần liên kết phiên bản gọi lại này và hàm mục tiêu thực tế
(CbOne). Lưu ý ở trên rằng CbOne có cùng loại chữ ký hàm như lệnh gọi lại--
cái này quan trọng. Chúng ta có thể chuyển bất kỳ hàm nào được gõ đúng như vậy vào hàm gọi lại này.
Chúng ta hãy xem xét điều này kỹ hơn:

tĩnh kép CbOne (double a, double b) {}
^ ^ ^
| | |
| | |
Gọi lại một;

Bạn chỉ có thể liên kết một hàm với một lệnh gọi lại nếu chúng có chữ ký trùng khớp. đầu tiên
đối số mẫu là kiểu trả về và các đối số mẫu bổ sung là kiểu
của các đối số của chữ ký hàm.

Bây giờ, hãy liên kết lệnh gọi lại "one" của chúng ta với hàm khớp với chữ ký của nó:

// xây dựng phiên bản gọi lại trỏ đến hàm cbOne
một = MakeCallback (&CbOne);

Cuộc gọi này tới gọi lại về bản chất là tạo ra một trong những hàm số chuyên dụng
đã đề cập ở trên. Biến được khai báo bằng cách sử dụng Gọi lại chức năng mẫu sẽ
đang đóng vai trò của hàm tổng quát. Nhiệm vụ một = gọi lại (&CbOne) is
dàn diễn viên chuyển đổi functor chuyên dụng mà callee biết thành functor chung
được người gọi biết đến.

Sau đó, trong chương trình, nếu cần gọi lại, nó có thể được sử dụng như sau:

NS_ASSERT (!one.IsNull ());

// gọi hàm cbOne thông qua thể hiện gọi lại
retOne đôi;
retOne = một (10.0, 20.0);

Việc kiểm tra cho IsNull() đảm bảo rằng lệnh gọi lại không rỗng -- rằng có một hàm
để gọi đằng sau cuộc gọi lại này. Sau đó, một() thực hiện chung nhà điều hành() đó thực sự là
quá tải với việc triển khai cụ thể của nhà điều hành() và trả về kết quả tương tự như thể
CbOne() đã được gọi trực tiếp.

Sử dụng các Gọi lại API với hội viên chức năng
Nói chung, bạn sẽ không gọi các hàm tĩnh mà thay vào đó là các hàm thành viên công khai của
một đối tượng. Trong trường hợp này, cần có một đối số bổ sung cho hàm MakeCallback để
cho hệ thống biết hàm sẽ được gọi trên đối tượng nào. Hãy xem xét ví dụ này,
cũng từ main-callback.cc:

lớp MyCb {
công khai:
int CbTwo (gấp đôi a) {
std::cout << "gọi cbTwo a=" << a << std::endl;
trả về -5;
}
};

intmain ()
{
...
// kiểu trả về: int
// kiểu đối số đầu tiên: double
Gọi lại hai;
cb MyCb;
// xây dựng phiên bản gọi lại trỏ đến MyCb::cbTwo
two = MakeCallback (&MyCb::CbTwo, &cb);
...
}

Ở đây, chúng ta chuyển một con trỏ đối tượng bổ sung tới Thực hiệnGọi lại<> chức năng. Nhớ lại từ
phần nền phía trên đó Nhà điều hành() sẽ sử dụng cú pháp con trỏ tới thành viên khi nó
thực thi trên một đối tượng:

toán tử int ảo() (ARG arg)
{
(*m_p.*m_pmi)(arg);
}

Và vì vậy chúng tôi cần cung cấp hai biến (m_pm_pmi) khi chúng tôi thực hiện cụ thể
functor. Dòng:

two = MakeCallback (&MyCb::CbTwo, &cb);

thực hiện chính xác điều đó. Trong trường hợp này, khi hai () Được gọi:

kết quả int = hai (1.0);

sẽ dẫn đến một cuộc gọi đến CbHai hàm thành viên (phương thức) trên đối tượng được trỏ tới bởi
&cb.

Xây dựng Null Gọi lại
Có thể các cuộc gọi lại là null; do đó có thể là điều khôn ngoan nếu bạn kiểm tra trước khi sử dụng chúng.
Có một cấu trúc đặc biệt cho lệnh gọi lại null, tốt hơn là chỉ chuyển qua
"0" làm đối số; nó là MakeNullCallback<> xây dựng:

hai = MakeNullCallback ();
NS_ASSERT (hai.IsNull());

Gọi một lệnh gọi lại null cũng giống như gọi một con trỏ hàm null: nó sẽ gặp sự cố tại
thời gian chạy.

Giới hạn Gọi lại
Một phần mở rộng rất hữu ích cho khái niệm functor là Gọi lại ràng buộc. Trước đây nó
đã đề cập rằng các bao đóng ban đầu là các lệnh gọi hàm được đóng gói để sử dụng sau này
chấp hành. Lưu ý rằng trong tất cả các mô tả Gọi lại ở trên, không có cách nào để
đóng gói mọi tham số để sử dụng sau -- khi Gọi lại được gọi thông qua nhà điều hành().
Tất cả các tham số được cung cấp bởi chức năng gọi.

Điều gì sẽ xảy ra nếu bạn muốn cho phép chức năng máy khách (chức năng cung cấp lệnh gọi lại)
cung cấp một số thông số? Alexandrescu gọi quá trình cho phép khách hàng
chỉ định một trong các tham số "ràng buộc". Một trong những thông số của nhà điều hành() đã
bị ràng buộc (cố định) bởi khách hàng.

Một số mã theo dõi pcap của chúng tôi cung cấp một ví dụ hay về điều này. Có một chức năng đó
cần được gọi bất cứ khi nào nhận được gói tin. Hàm này gọi một đối tượng
thực sự ghi gói vào đĩa ở định dạng tệp pcap. Chữ ký của một trong số đó
chức năng sẽ là:

static void DefaultSink (Ptr tập tin, Ptr P);

Từ khóa tĩnh có nghĩa đây là một hàm tĩnh không cần điều này con trỏ, vậy
nó sẽ sử dụng lệnh gọi lại kiểu C. Chúng tôi không muốn mã gọi điện phải biết về
bất cứ thứ gì ngoại trừ Gói. Những gì chúng tôi muốn trong mã gọi điện chỉ là một lệnh gọi trông giống như:

m_promiscSnifferTrace (m_currentPkt);

Điều chúng tôi muốn làm là ràng buộc các Ptr hồ sơ đến cuộc gọi lại cụ thể
thực hiện khi nó được tạo ra và sắp xếp cho nhà điều hành() của cuộc gọi lại tới
cung cấp thông số đó miễn phí.

Chúng tôi cung cấp MakeBoundGọi lại chức năng mẫu cho mục đích đó. Nó cũng giống như vậy
các thông số như gọi lại hàm mẫu nhưng cũng lấy các tham số
ràng buộc. Trong trường hợp ví dụ trên:

MakeBoundCallback (&DefaultSink, tệp);

sẽ tạo ra một triển khai gọi lại cụ thể có thể thêm vào giới hạn bổ sung
tranh luận. Về mặt khái niệm, nó mở rộng hàm chức năng cụ thể được mô tả ở trên với một hoặc nhiều
đối số ràng buộc:

bản mẫu
lớp cụ thểFunctor : Functor công cộng
{
công khai:
Cụ thể(T* p, int (T::*_pmi)(ARG arg), BOUND_ARGboundArg)
{
m_p = p;
m_pmi = chiều;
m_boundArg = giới hạnArg;
}

toán tử int ảo() (ARG arg)
{
(*m_p.*m_pmi)(m_boundArg, arg);
}
riêng tư:
void (T::*m_pmi)(ARG arg);
T* m_p;
BOUND_ARG m_boundArg;
};

Bạn có thể thấy rằng khi một functor cụ thể được tạo ra, đối số liên kết sẽ được lưu trong
chính đối tượng functor/gọi lại. Khi mà nhà điều hành() được gọi với đơn
tham số, như trong:

m_promiscSnifferTrace (m_currentPkt);

việc thực hiện nhà điều hành() thêm tham số bị ràng buộc vào lệnh gọi hàm thực tế:

(*m_p.*m_pmi)(m_boundArg, arg);

Cũng có thể liên kết hai hoặc ba đối số. Giả sử chúng ta có một hàm với
Chữ ký:

khoảng trống tĩnh NotifyEvent (Ptr a, Ptr b, MyEventType e);

Người ta có thể tạo ràng buộc gọi lại ràng buộc hai đối số đầu tiên như:

MakeBoundCallback (&NotifyEvent, a1, b1);

giả định a1b1 là những đối tượng thuộc loại AB tương ứng. Tương tự cho ba
đối số người ta sẽ có chức năng với chữ ký:

khoảng trống tĩnh NotifyEvent (Ptr a, Ptr b, MyEventType e);

Ràng buộc ba đối số được thực hiện với:

MakeBoundCallback (&NotifyEvent, a1, b1, c1);

một lần nữa giả định a1, b1c1 là những đối tượng thuộc loại A, BC tương ứng.

Loại liên kết này có thể được sử dụng để trao đổi thông tin giữa các đối tượng trong mô phỏng;
cụ thể, các cuộc gọi lại bị ràng buộc có thể được sử dụng làm các cuộc gọi lại được theo dõi, sẽ được mô tả trong
phần tiếp theo.

Truy Gọi lại
Placeholder phần phụ

Gọi lại . Các địa điểm in ns-3
Lệnh gọi lại thường được sử dụng ở đâu trong ns-3? Dưới đây là một số trong những cái dễ thấy hơn
người dùng điển hình:

· API ổ cắm

· API lớp 2/lớp 3

· Hệ thống con truy tìm

· API giữa IP và các hệ thống con định tuyến

Triển khai hệ thống chi tiết
Các đoạn mã ở trên rất đơn giản và chỉ được thiết kế để minh họa cơ chế
chính nó. Mã gọi lại thực tế khá phức tạp và có cường độ mẫu cao và
sự hiểu biết sâu sắc về mã là không cần thiết. Nếu quan tâm, người dùng chuyên gia có thể tìm thấy
sau đây hữu ích.

Mã ban đầu được viết dựa trên các kỹ thuật được mô tả trong
http://www.codeproject.com/cpp/TTLFunction.asp. Sau đó nó đã được viết lại để làm theo
kiến trúc được nêu trong hiện đại C + + Thiết kế, Chung Lập trình Thiết kế Patterns
Đã áp dụng, Alexandrescu, chương 5, Tổng quát hóa hàm số.

Mã này sử dụng:

· Các tham số mẫu mặc định giúp người dùng không phải chỉ định các tham số trống khi
số lượng tham số nhỏ hơn số lượng được hỗ trợ tối đa

· Thành ngữ pimpl: lớp Callback được truyền theo giá trị và ủy quyền cho điểm mấu chốt của
công việc đến con trỏ nổi mụn của nó.

· Có thể sử dụng hai cách triển khai pimpl bắt nguồn từ CallbackImpl FunctorCallbackImpl
với bất kỳ loại functor nào trong khi MemPtrCallbackImpl có thể được sử dụng với các con trỏ tới thành viên
chức năng.

· Triển khai danh sách tham chiếu để triển khai ngữ nghĩa giá trị của Gọi lại.

Mã này đáng chú ý nhất là khác với việc triển khai Alexandrescu ở chỗ nó không
sử dụng danh sách loại để chỉ định và chuyển các loại đối số gọi lại. Tất nhiên rồi,
nó cũng không sử dụng ngữ nghĩa phá hủy bản sao và dựa vào danh sách tham chiếu thay vì
autoPtr để giữ con trỏ.

Đối tượng kiểu mẫu
ns-3 về cơ bản là một hệ thống đối tượng C++. Các đối tượng có thể được khai báo và khởi tạo như
thông thường, theo quy tắc C++. ns-3 cũng bổ sung thêm một số tính năng cho các đối tượng C++ truyền thống, như
được mô tả dưới đây, để cung cấp chức năng và tính năng tốt hơn. Chương hướng dẫn này là
nhằm giới thiệu với người đọc về ns-3 mô hình đối tượng

Phần này mô tả thiết kế lớp C++ cho ns-3 các đối tượng. Tóm lại, một số thiết kế
các mẫu được sử dụng bao gồm thiết kế hướng đối tượng cổ điển (giao diện đa hình và
triển khai), tách biệt giao diện và triển khai, công cộng phi ảo
mẫu thiết kế giao diện, cơ sở tổng hợp đối tượng và tính toán tham chiếu cho
quản lý bộ nhớ. Những người quen thuộc với các mô hình thành phần như COM hoặc Bonobo sẽ
nhận biết các yếu tố của thiết kế trong ns-3 mô hình tập hợp đối tượng, mặc dù ns-3
thiết kế cũng không tuân thủ nghiêm ngặt.

Hướng đối tượng hành vi
Các đối tượng C++, nói chung, cung cấp các khả năng hướng đối tượng chung (trừu tượng hóa,
đóng gói, kế thừa và đa hình) là một phần của hướng đối tượng cổ điển
thiết kế. ns-3 các đối tượng sử dụng các thuộc tính này; ví dụ:

địa chỉ lớp học
{
công khai:
Địa chỉ ();
Địa chỉ (loại uint8_t, const uint8_t *buffer, uint8_t len);
Địa chỉ (const Địa chỉ & địa chỉ);
Địa chỉ &operator = (const Địa chỉ &địa chỉ);
...
riêng tư:
uint8_t m_type;
uint8_t m_len;
...
};

Đối tượng cơ sở các lớp học
Có ba lớp cơ sở đặc biệt được sử dụng trong ns-3. Các lớp kế thừa từ các cơ sở này
các lớp có thể khởi tạo các đối tượng có thuộc tính đặc biệt. Các lớp cơ sở này là:

· lớp Đối tượng

· lớp Cơ sở đối tượng

· lớp Số lượng tham chiếu đơn giản

Không bắt buộc phải như vậy ns-3 các đối tượng kế thừa từ các lớp này, nhưng những đối tượng nhận được
tính chất đặc biệt. Các lớp bắt nguồn từ lớp Đối tượng nhận được các tính chất sau.

· NS ns-3 hệ thống loại và thuộc tính (xem Thuộc tính)

· một hệ thống tập hợp đối tượng

· hệ thống đếm tham chiếu con trỏ thông minh (lớp Ptr)

Các lớp bắt nguồn từ lớp Cơ sở đối tượng có được hai thuộc tính đầu tiên ở trên, nhưng không
có được con trỏ thông minh. Các lớp bắt nguồn từ lớp Số lượng tham chiếu đơn giản: chỉ nhận được
hệ thống đếm tham chiếu con trỏ thông minh.

Trong thực tế, lớp Đối tượng là biến thể của ba điều trên mà ns-3 nhà phát triển sẽ
thường gặp nhất.

Bộ nhớ quản lý tốt nghiệp lớp XNUMX ptr
Quản lý bộ nhớ trong chương trình C++ là một quá trình phức tạp và thường được thực hiện không chính xác hoặc
không nhất quán. Chúng tôi đã giải quyết một thiết kế đếm tham chiếu được mô tả như sau.

Tất cả các đối tượng sử dụng tính năng tham chiếu đều duy trì số lượng tham chiếu nội bộ để xác định
khi một đối tượng có thể tự xóa chính nó một cách an toàn. Mỗi lần một con trỏ được lấy tới một
giao diện, số lượng tham chiếu của đối tượng được tăng lên bằng cách gọi Tham khảo(). Đây là
nghĩa vụ của người sử dụng con trỏ phải rõ ràng Unref() con trỏ khi hoàn tất. Khi
số lượng tham chiếu giảm xuống 0, đối tượng sẽ bị xóa.

· Khi mã máy khách nhận được một con trỏ từ chính đối tượng đó thông qua việc tạo đối tượng,
hoặc thông qua GetObject, nó không phải tăng số lượng tham chiếu.

· Khi mã máy khách nhận được một con trỏ từ một nguồn khác (ví dụ, sao chép một con trỏ), nó phải
cuộc gọi Tham khảo() để tăng số lượng tham chiếu.

· Tất cả người dùng con trỏ đối tượng phải gọi Unref() để phát hành tài liệu tham khảo.

Gánh nặng khi gọi điện Unref() phần nào nhẹ nhõm hơn khi sử dụng cách tính tham chiếu
lớp con trỏ thông minh được mô tả dưới đây.

Người dùng sử dụng API cấp thấp muốn phân bổ rõ ràng các đối tượng không được tính tham chiếu
trên heap, sử dụng toán tử mới, chịu trách nhiệm xóa các đối tượng đó.

Tài liệu tham khảo hơn nữa thông minh con trỏ (Ptr)
đang gọi Tham khảo()Unref() lúc nào cũng sẽ cồng kềnh, vì vậy ns-3 cung cấp một thông minh
lớp con trỏ ptr tương tự như Tăng cường::intrusive_ptr. Lớp con trỏ thông minh này giả định rằng
loại cơ bản cung cấp một cặp refBỏ giới thiệu các phương pháp dự kiến ​​sẽ
tăng và giảm số lần đếm nội bộ của đối tượng.

Việc triển khai này cho phép bạn thao tác con trỏ thông minh như thể nó là một con trỏ bình thường
con trỏ: bạn có thể so sánh nó với số 0, so sánh nó với các con trỏ khác, gán số 0 cho
nó, v.v.

Có thể trích xuất con trỏ thô từ con trỏ thông minh này bằng GetPointer()
PeekPointer() phương pháp.

Nếu bạn muốn lưu trữ một đối tượng mới vào một con trỏ thông minh, chúng tôi khuyên bạn nên sử dụng
Mẫu CreateObject có chức năng tạo đối tượng và lưu trữ nó trong một con trỏ thông minh để
tránh rò rỉ bộ nhớ. Các chức năng này thực sự là những chức năng tiện lợi nhỏ và mục tiêu của chúng
chỉ là để giúp bạn tiết kiệm một chút thời gian gõ phím.

Tạo đối tượng Tạo
Các đối tượng trong C++ có thể được tạo tĩnh, động hoặc tự động. Điều này đúng
cho ns-3 cũng có, nhưng một số đối tượng trong hệ thống có sẵn một số khung bổ sung.
Cụ thể, các đối tượng được tính tham chiếu thường được phân bổ bằng cách sử dụng Tạo hoặc tạo khuôn mẫu
Phương thức CreateObject như sau.

Đối với các đối tượng xuất phát từ lớp Đối tượng:

Ptr thiết bị = CreateObject ();

Vui lòng không tạo các đối tượng như vậy bằng cách sử dụng nhà điều hành người mới; tạo chúng bằng cách sử dụng CreateObject ()
thay thế.

Đối với các đối tượng xuất phát từ lớp Số lượng tham chiếu đơn giảnhoặc các đối tượng khác hỗ trợ việc sử dụng
lớp con trỏ thông minh, một chức năng trợ giúp theo khuôn mẫu có sẵn và được khuyến nghị sử dụng:

Ptr b = Tạo ();

Đây chỉ đơn giản là một trình bao bọc xung quanh toán tử mới xử lý chính xác việc đếm tham chiếu
hệ thống.

Tóm lại, sử dụng Tạo nên nếu B không phải là một đối tượng mà chỉ sử dụng tính tham chiếu (ví dụ:
Gói), Và sử dụng Tạo đối tượng nếu B xuất phát từ ns3 :: Đối tượng.

aggregation
ns-3 hệ thống tập hợp đối tượng được thúc đẩy một phần mạnh mẽ bởi sự thừa nhận rằng một
trường hợp sử dụng chung cho ns-2 đã sử dụng tính kế thừa và tính đa hình để mở rộng
các mô hình giao thức. Ví dụ, các phiên bản chuyên dụng của TCP như RenoTcpAgent lấy được
từ (và ghi đè các hàm từ) lớp TcpAgent.

Tuy nhiên, có hai vấn đề nảy sinh trong ns-2 mô hình đang bị hạ thấp và "cơ sở yếu
class." Downcasting đề cập đến thủ tục sử dụng một con trỏ lớp cơ sở tới một đối tượng và
truy vấn nó trong thời gian chạy để tìm ra thông tin loại, được sử dụng để truyền con trỏ một cách rõ ràng
tới một con trỏ lớp con để có thể sử dụng API lớp con. Lớp cơ sở yếu đề cập đến
các vấn đề nảy sinh khi một lớp không thể được tái sử dụng một cách hiệu quả (bắt nguồn từ) bởi vì nó
thiếu chức năng cần thiết, khiến nhà phát triển phải sửa đổi lớp cơ sở và
gây ra sự gia tăng các lệnh gọi API lớp cơ sở, một số trong đó có thể không có ngữ nghĩa
đúng cho tất cả các lớp con.

ns-3 đang sử dụng một phiên bản của mẫu thiết kế giao diện truy vấn để tránh những vấn đề này.
Thiết kế này dựa trên các yếu tố của Thành phần Đối tượng MẫuGNOME Bonobo mặc dù
khả năng tương thích đầy đủ ở cấp độ nhị phân của các thành phần có thể thay thế không được hỗ trợ và chúng tôi có
đã cố gắng đơn giản hóa cú pháp và tác động đến các nhà phát triển mô hình.

Các ví dụ
aggregation ví dụ
Node là một ví dụ điển hình về việc sử dụng tổng hợp trong ns-3. Lưu ý rằng không có nguồn gốc
các lớp nút trong ns-3 chẳng hạn như lớp Nút Internet. Thay vào đó, các thành phần (giao thức) được
tổng hợp thành một nút. Hãy xem cách một số giao thức IPv4 được thêm vào một nút.:

khoảng trống tĩnh
AddIpv4Stack(Ptr nút)
{
Ptr ipv4 = CreateObject ();
ipv4->SetNode (nút);
nút->AggregateObject (ipv4);
Ptr ipv4Impl = CreateObject ();
ipv4Impl->SetIpv4 (ipv4);
nút->AggregateObject (ipv4Impl);
}

Lưu ý rằng các giao thức IPv4 được tạo bằng cách sử dụng CreateObject (). Sau đó, chúng được tổng hợp
đến nút. Theo cách này, lớp cơ sở Node không cần phải chỉnh sửa để cho phép người dùng
với một con trỏ Node lớp cơ sở để truy cập vào giao diện Ipv4; người dùng có thể yêu cầu nút cho một
con trỏ tới giao diện IPv4 của nó khi chạy. Cách người dùng yêu cầu nút được mô tả trong
tiểu mục tiếp theo.

Lưu ý rằng đó là lỗi lập trình khi tổng hợp nhiều đối tượng cùng loại thành
an ns3 :: Đối tượng. Vì vậy, ví dụ, việc tổng hợp không phải là một lựa chọn để lưu trữ tất cả
ổ cắm hoạt động của một nút.

Nhận đối tượng ví dụ
GetObject là một cách an toàn về kiểu để đạt được khả năng truyền phát an toàn và cho phép các giao diện được
tìm thấy trên một đối tượng.

Hãy xem xét một con trỏ nút m_node trỏ đến một đối tượng Node có triển khai
IPv4 trước đây được tổng hợp vào nó. Mã máy khách muốn định cấu hình tuyến đường mặc định. ĐẾN
làm như vậy, nó phải truy cập vào một đối tượng trong nút có giao diện chuyển tiếp IP
cấu hình. Nó thực hiện như sau:

Ptr ipv4 = m_node->GetObject ();

Nếu nút trên thực tế không có đối tượng Ipv4 được tổng hợp vào nó thì phương thức sẽ
trả về giá trị rỗng. Vì vậy, cách tốt nhất là kiểm tra giá trị trả về từ một hàm như vậy
gọi. Nếu thành công, người dùng hiện có thể sử dụng Ptr cho đối tượng Ipv4 trước đây
tổng hợp vào nút.

Một ví dụ khác về cách người ta có thể sử dụng tính năng tổng hợp là thêm các mô hình tùy chọn vào các đối tượng. Vì
Ví dụ, một đối tượng Node hiện có có thể có một đối tượng "Mô hình năng lượng" được tổng hợp vào nó tại
thời gian chạy (không sửa đổi và biên dịch lại lớp nút). Một mô hình hiện có (chẳng hạn như một
thiết bị mạng không dây) sau đó có thể "GetObject" cho mô hình năng lượng và hành động phù hợp
nếu giao diện đã được tích hợp vào đối tượng Node cơ bản hoặc được tổng hợp thành
nó vào thời gian chạy. Tuy nhiên, các nút khác không cần biết gì về mô hình năng lượng.

Chúng tôi hy vọng rằng chế độ lập trình này sẽ đòi hỏi các nhà phát triển ít phải sửa đổi hơn nhiều
các lớp cơ sở.

Đối tượng nhà máy
Trường hợp sử dụng phổ biến là tạo nhiều đối tượng có cấu hình tương tự nhau. Người ta có thể lặp đi lặp lại
cuộc gọi CreateObject () nhưng cũng có một mẫu thiết kế nhà máy được sử dụng trong ns-3 hệ thống.
Nó được sử dụng nhiều trong API "trợ giúp".

Lớp Đối tượngNhà máy có thể được sử dụng để khởi tạo các đối tượng và cấu hình các thuộc tính trên
những đồ vật đó:

void SetTypeId (TypeId tid);
bộ void (std::tên chuỗi, const AttributionValue &value);
Ptr Tạo (void) const;

Phương pháp đầu tiên cho phép người ta sử dụng ns-3 Hệ thống TypeId để xác định loại đối tượng
tạo. Cái thứ hai cho phép người ta thiết lập các thuộc tính trên các đối tượng được tạo và
thứ ba cho phép người ta tự tạo các đối tượng.

Ví dụ:

nhà máy ObjectFactory;
// Làm cho nhà máy này tạo các đối tượng kiểu FriisPropagationLossModel
Factory.SetTypeId ("ns3::FriisPropagationLossModel")
// Làm cho đối tượng Factory này thay đổi giá trị mặc định của một thuộc tính, ví dụ
// các đối tượng được tạo sau đó
Factory.Set ("SystemLoss", DoubleValue (2.0));
// Tạo một đối tượng như vậy
Ptr đối tượng = nhà máy.Tạo ();
Factory.Set ("SystemLoss", DoubleValue (3.0));
// Tạo một đối tượng khác với SystemLoss khác
Ptr đối tượng = nhà máy.Tạo ();

buồn bã
Một câu hỏi đã được đặt ra nhiều lần là "Nếu tôi có một con trỏ lớp cơ sở (Ptr) tới một
đối tượng và tôi muốn con trỏ lớp dẫn xuất, tôi có nên hạ thấp (thông qua diễn biến động C++) xuống
lấy con trỏ dẫn xuất, hay tôi nên sử dụng hệ thống tập hợp đối tượng để GetObject<> ()
để tìm Ptr cho giao diện của API lớp con?"

Câu trả lời cho điều này là trong nhiều tình huống, cả hai kỹ thuật đều có tác dụng. ns-3 cung cấp một
Hàm tạo khuôn mẫu để tạo cú pháp truyền động đối tượng cho nhiều người dùng hơn
thân thiện:

bản mẫu
Ptr
DynamicCast (Ptr const&p)
{
trả lại Ptr (dynamic_cast (PeekPulum (p)));
}

DynamicCast hoạt động khi lập trình viên có một con trỏ kiểu cơ sở và đang kiểm tra một
con trỏ lớp con. GetObject hoạt động khi tìm kiếm các đối tượng khác nhau được tổng hợp, nhưng cũng
hoạt động với các lớp con giống như DynamicCast. Nếu không chắc chắn, người lập trình nên
sử dụng GetObject, vì nó hoạt động trong mọi trường hợp. Nếu người lập trình biết hệ thống phân cấp lớp của
đối tượng đang được xem xét, sẽ trực tiếp hơn nếu chỉ sử dụng DynamicCast.

Cấu hình Thuộc tính
In ns-3 mô phỏng, có hai khía cạnh chính đối với cấu hình:

· Cấu trúc liên kết mô phỏng và cách các đối tượng được kết nối.

· Các giá trị được sử dụng bởi các mô hình được khởi tạo trong cấu trúc liên kết.

Chương này tập trung vào mục thứ hai ở trên: có bao nhiêu giá trị được sử dụng trong ns-3 đang
được tổ chức, ghi chép và sửa đổi bởi ns-3 người dùng. Các ns-3 hệ thống thuộc tính cũng là
nền tảng về cách thu thập dấu vết và số liệu thống kê trong trình mô phỏng.

Trong chương này chúng ta sẽ thảo luận về những cách khác nhau để thiết lập hoặc sửa đổi các giá trị
được sử dụng bởi ns-3 các đối tượng mô hình Theo thứ tự cụ thể tăng dần, đó là:

┌──────────────────────────────────── ────────────────────┐
│Phương pháp │ Phạm vi │
├──────────────────────────────────── ────────────────────┤
│Đặt giá trị thuộc tính mặc định │ Ảnh hưởng đến tất cả các phiên bản của │
│khi Thuộc tính được xác định trong lớp │. │
GetTypeId (). │ │
└──────────────────────────────────── ────────────────────┘

Dòng lệnh │ Ảnh hưởng đến tất cả các trường hợp trong tương lai. │
Cấu hình::SetDefault() │ │
Cửa hàng cấu hình │ │
├──────────────────────────────────── ────────────────────┤
Đối tượngNhà máy │ Ảnh hưởng đến tất cả các phiên bản được tạo │
│ │ với nhà máy. │
├──────────────────────────────────── ────────────────────┤
XHelperSetThuộc tính () │ Ảnh hưởng đến tất cả các phiên bản được tạo bởi │
│ │ người giúp đỡ. │
├──────────────────────────────────── ────────────────────┤
MyClass::SetX () │ Thay đổi trường hợp cụ thể này. │
Đối tượng::SetAttribution () │ Nói chung đây là hình thức duy nhất │
Cấu hình::Set() │ có thể được lên lịch để thay đổi │
│ │ một phiên bản sau khi mô phỏng │
│ │ đang chạy. │
└──────────────────────────────────── ────────────────────┘

Theo "tính đặc hiệu", chúng tôi muốn nói rằng các phương thức ở các hàng sau trong bảng sẽ ghi đè các giá trị được đặt
bởi và thường ảnh hưởng đến ít trường hợp hơn các phương pháp trước đó.

Trước khi đi sâu vào chi tiết của hệ thống giá trị thuộc tính, sẽ giúp xem xét một số
thuộc tính cơ bản của lớp Đối tượng.

Đối tượng Giới thiệu chung
ns-3 về cơ bản là một hệ thống dựa trên đối tượng C++. Bằng cách này, chúng tôi muốn nói rằng các lớp C++ mới
(loại) có thể được khai báo, định nghĩa và phân lớp như bình thường.

nhiều ns-3 các đối tượng kế thừa từ Đối tượng lớp cơ sở. Những đối tượng này có thêm một số
các thuộc tính mà chúng tôi khai thác để tổ chức hệ thống và cải thiện việc quản lý bộ nhớ
của các đối tượng của chúng tôi:

· Hệ thống "Siêu dữ liệu" liên kết tên lớp với rất nhiều siêu thông tin về
đối tượng, bao gồm:

· Lớp cơ sở của lớp con,

· Tập hợp các hàm tạo có thể truy cập được trong lớp con,

· Tập hợp các thuộc tính của lớp con,

· Mỗi thuộc tính có thể được đặt hay chỉ đọc,

· Khoảng giá trị cho phép của từng thuộc tính.

· Thực hiện con trỏ thông minh đếm tham chiếu, để quản lý bộ nhớ.

ns-3 các đối tượng sử dụng hệ thống thuộc tính xuất phát từ một trong hai Đối tượng or Cơ sở đối tượng. Phần lớn
ns-3 các đối tượng chúng ta sẽ thảo luận bắt nguồn từ Đối tượng, nhưng một số ít nằm ngoài phạm vi thông minh
Khung quản lý bộ nhớ con trỏ bắt nguồn từ Cơ sở đối tượng.

Hãy xem xét một vài thuộc tính của các đối tượng này.

Thông minh con trỏ
Như đã giới thiệu ở ns-3 hướng dẫn, ns-3 đối tượng là bộ nhớ được quản lý bởi một tài liệu tham khảo
hơn nữa thông minh con trỏ thực hiện, lớp học ptr.

Con trỏ thông minh được sử dụng rộng rãi trong ns-3 API, để tránh chuyển các tham chiếu tới
các đối tượng được phân bổ heap có thể gây rò rỉ bộ nhớ. Đối với hầu hết cách sử dụng cơ bản (cú pháp), hãy xử lý
một con trỏ thông minh giống như một con trỏ thông thường:

Ptr nd = ...;
nd->CallSomeFunction ();
// vân vân.

Vậy làm thế nào để bạn có được một con trỏ thông minh tới một đối tượng, như trong dòng đầu tiên của ví dụ này?

Tạo đối tượng
Như chúng ta đã thảo luận ở trên trong Memory-management-and-class-Ptr, ở API cấp thấp nhất, các đối tượng
loại Đối tượng không được khởi tạo bằng cách sử dụng nhà điều hành người mới như thường lệ nhưng thay vào đó bằng một khuôn mẫu
chức năng được gọi là Tạo đối tượng ().

Một cách điển hình để tạo một đối tượng như sau:

Ptr nd = CreateObject ();

Bạn có thể coi đây là chức năng tương đương với:

WifiNetDevice* nd = WifiNetDevice mới ();

Các đối tượng xuất phát từ Đối tượng phải được phân bổ trên heap bằng cách sử dụng Tạo đối tượng (). Những, cái đó
Bắt nguồn từ Cơ sở đối tượng, Chẳng hạn như ns-3 các chức năng trợ giúp và các tiêu đề và đoạn giới thiệu gói,
có thể được cấp phát trên ngăn xếp.

Trong một số tập lệnh, bạn có thể không thấy nhiều Tạo đối tượng () cuộc gọi trong mã; đây là
bởi vì thực tế có một số đối tượng trợ giúp đang thực hiện Tạo đối tượng () cuộc gọi
cho bạn.

loạiId
ns-3 các lớp bắt nguồn từ lớp Đối tượng có thể bao gồm một lớp siêu dữ liệu được gọi là loạiId việc này
ghi lại thông tin meta về lớp, để sử dụng trong tập hợp đối tượng và thành phần
hệ thống quản lý:

· Một chuỗi duy nhất xác định lớp.

· Lớp cơ sở của lớp con, trong hệ thống siêu dữ liệu.

· Tập hợp các hàm tạo có thể truy cập được trong lớp con.

· Danh sách các thuộc tính có thể truy cập công khai ("thuộc tính") của lớp.

Đối tượng Tổng kết
Đặt tất cả các khái niệm này lại với nhau, chúng ta hãy xem một ví dụ cụ thể: lớp Node.

Tệp tiêu đề công khai nút.h có một tuyên bố bao gồm một tĩnh GetTypeId ()
hàm gọi:

nút lớp: Đối tượng công cộng
{
công khai:
TypeId tĩnh GetTypeId (void);
...

Điều này được xác định trong nút.cc tập tin như sau:

loạiId
Nút::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Node")
.SetParent ()
.AddConstructor ()
.AddAttribution ("Danh sách thiết bị",
"Danh sách các thiết bị được liên kết với Nút này.",
Giá trị đối tượngVector (),
MakeObjectVectorAccessor (&Node::m_devices),
MakeObjectVectorChecker ())
.AddAttribution ("Danh sách ứng dụng",
"Danh sách các ứng dụng được liên kết với Nút này.",
Giá trị đối tượngVector (),
MakeObjectVectorAccessor (&Node::m_applications),
MakeObjectVectorChecker ())
.AddAttribution ("Id",
"Id (số nguyên duy nhất) của Nút này.",
TypeId::ATTR_GET, // chỉ cho phép lấy nó.
UintegerValue (0),
MakeUintegerAccessor (&Node::m_id),
MakeUintegerChecker ())
;
trả lại tid;
}

Xem xét loạiId của ns-3 Đối tượng lớp như một dạng mở rộng của loại thời gian chạy
thông tin (RTTI). Ngôn ngữ C++ bao gồm một loại RTTI đơn giản để hỗ trợ
động_castngười đánh chữ khai thác.

SetParent () cuộc gọi trong định nghĩa trên được sử dụng cùng với
cơ chế tổng hợp đối tượng để cho phép truyền lên và xuống an toàn trong cây kế thừa
suốt trong Nhận đối tượng (). Nó cũng cho phép các lớp con kế thừa các Thuộc tính của lớp cha của chúng
lớp học.

AddConstructor () cuộc gọi được sử dụng cùng với nhà máy đối tượng trừu tượng của chúng tôi
cơ chế cho phép chúng ta xây dựng các đối tượng C++ mà không buộc người dùng phải biết
lớp cụ thể của đối tượng cô ấy đang xây dựng.

Ba cuộc gọi đến Thêm thuộc tính () liên kết một chuỗi nhất định với một giá trị được gõ mạnh trong
lớp. Lưu ý rằng bạn phải cung cấp chuỗi trợ giúp có thể được hiển thị, ví dụ:
thông qua bộ xử lý dòng lệnh. Mỗi đặc tính được liên kết với các cơ chế truy cập
biến thành viên cơ bản trong đối tượng (ví dụ: MakeUintegerAccessor () nói
cái chung đặc tính mã cách lấy ID nút ở trên). Ngoài ra còn có "Người kiểm tra"
các phương pháp được sử dụng để xác thực các giá trị theo các giới hạn phạm vi, chẳng hạn như giá trị tối đa và
giá trị tối thiểu cho phép.

Khi người dùng muốn tạo Nút, họ thường sẽ gọi một số dạng Tạo đối tượng (),:

Ptr n = CreateObject ();

hoặc trừu tượng hơn, bằng cách sử dụng một nhà máy đối tượng, bạn có thể tạo một Node đối tượng thậm chí không có
biết loại C++ cụ thể:

nhà máy ObjectFactory;
const std::string typeId = "ns3::Node'';
nhà máy.SetTypeId (typeId);
Ptr nút = nhà máy.Tạo ();

Cả hai phương pháp này đều dẫn đến các thuộc tính được khởi tạo đầy đủ có sẵn trong
kết quả Đối tượng các trường hợp.

Tiếp theo chúng ta thảo luận về cách các thuộc tính (giá trị liên kết với các biến thành viên hoặc hàm của
lớp) được đưa vào phần trên loạiId.

Thuộc tính
Mục tiêu của hệ thống thuộc tính là tổ chức việc truy cập các đối tượng thành viên bên trong của một
mô phỏng. Mục tiêu này nảy sinh bởi vì, thông thường trong mô phỏng, người dùng sẽ cắt và
dán/sửa đổi các tập lệnh mô phỏng hiện có hoặc sẽ sử dụng các cấu trúc mô phỏng cấp cao hơn,
nhưng thường sẽ quan tâm đến việc nghiên cứu hoặc truy tìm các biến số nội bộ cụ thể. Vì
ví dụ, các trường hợp sử dụng như:

· "I muốn đến theo dõi các gói on các không dây giao diện có thể on các Thành phố điện khí hóa phía tây dãy núi Rocky đầu tiên truy cập điểm."

· "I muốn đến theo dõi các giá trị of các TCP tắc nghẽn cửa sổ (mọi thời gian it thay đổi) on a
riêng TCP ổ cắm."

· "I muốn a đổ of tất cả các giá trị việc này đã sử dụng in my mô phỏng."

Tương tự, người dùng có thể muốn truy cập chi tiết vào các biến nội bộ trong mô phỏng hoặc
có thể muốn thay đổi rộng rãi giá trị ban đầu được sử dụng cho một tham số cụ thể trong tất cả
các đối tượng được tạo sau đó. Cuối cùng, người dùng có thể muốn biết những biến nào có thể cài đặt được.
và có thể truy xuất được trong cấu hình mô phỏng. Đây không chỉ là mô phỏng trực tiếp
tương tác trên dòng lệnh; cũng xem xét một giao diện người dùng đồ họa (tương lai)
muốn có thể cung cấp một tính năng theo đó người dùng có thể nhấp chuột phải vào một nút trên
canvas và xem danh sách các tham số được sắp xếp theo cấp bậc có thể thiết lập được trên
nút và các đối tượng thành viên cấu thành của nó, đồng thời văn bản trợ giúp và các giá trị mặc định cho mỗi nút
tham số.

Xác định Thuộc tính
Chúng tôi cung cấp một cách để người dùng truy cập các giá trị sâu trong hệ thống mà không cần phải tìm hiểu kỹ
người truy cập (con trỏ) thông qua hệ thống và đi theo chuỗi con trỏ để truy cập chúng. Hãy xem xét một
tốt nghiệp lớp XNUMX ThảĐuôiHàng Đợi có một biến thành viên là số nguyên không dấu m_maxGói;
biến thành viên này kiểm soát độ sâu của hàng đợi.

Nếu chúng ta nhìn vào tuyên bố của ThảĐuôiHàng Đợi, chúng ta thấy như sau:

lớp DropTailQueue : Hàng đợi công khai {
công khai:
TypeId tĩnh GetTypeId (void);
...

riêng tư:
std::hàng đợi > m_gói;
uint32_t m_maxPackets;
};

Hãy xem xét những điều mà người dùng có thể muốn thực hiện với giá trị của m_maxGói:

· Đặt một giá trị mặc định cho hệ thống, sao cho bất cứ khi nào có một giá trị mới ThảĐuôiHàng Đợi được tạo ra,
thành viên này được khởi tạo theo mặc định đó.

· Đặt hoặc nhận giá trị trên hàng đợi đã được khởi tạo.

Những điều trên thường yêu cầu cung cấp Thiết lập ()Nhận () chức năng và một số loại
giá trị mặc định toàn cầu.

Trong tạp chí ns-3 hệ thống thuộc tính, các định nghĩa giá trị này và đăng ký hàm truy cập
được chuyển vào loạiId lớp học; ví dụ.:

NS_OBJECT_ENSURE_REGISTERED (DropTailQueue);

loạiId
DropTailQueue::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::DropTailQueue")
.SetParent ()
.AddConstructor ()
.AddAttribution ("MaxPackets",
"Số lượng gói tối đa được chấp nhận bởi DropTailQueue này.",
UintegerValue (100),
MakeUintegerAccessor (&DropTailQueue::m_maxPackets),
MakeUintegerChecker ())
;

trả lại tid;
}

Thêm thuộc tính () phương pháp này đang thực hiện một số việc cho m_maxGói giá trị:

· Ràng buộc biến thành viên (thường là riêng tư) m_maxGói đến một chuỗi công khai
"Gói tối đa".

· Cung cấp giá trị mặc định (100 gói).

· Cung cấp một số văn bản trợ giúp xác định ý nghĩa của giá trị.

· Cung cấp một "Trình kiểm tra" (không được sử dụng trong ví dụ này) có thể được sử dụng để đặt giới hạn trên
khoảng giá trị cho phép.

Điểm mấu chốt là bây giờ giá trị của biến này và giá trị mặc định của nó có thể truy cập được
trong không gian tên thuộc tính, dựa trên các chuỗi như "Gói tối đa"loạiId tên
dây. Trong phần tiếp theo, chúng tôi sẽ cung cấp một tập lệnh mẫu cho thấy cách người dùng có thể
thao tác các giá trị này.

Lưu ý rằng việc khởi tạo thuộc tính phụ thuộc vào macro NS_OBJECT_ENSURE_REGISTERED
(DropTailQueue) được gọi là; nếu bạn bỏ điều này ra khỏi việc triển khai lớp mới,
các thuộc tính sẽ không được khởi tạo chính xác.

Mặc dù chúng tôi đã mô tả cách tạo thuộc tính nhưng vẫn chưa mô tả cách truy cập
và quản lý các giá trị này. Ví dụ, không có toàn cầu.h tập tin tiêu đề nơi đây
được lưu trữ; các thuộc tính được lưu trữ cùng với các lớp của chúng. Những câu hỏi nảy sinh một cách tự nhiên là làm thế nào
người dùng có dễ dàng tìm hiểu về tất cả các thuộc tính của mô hình của họ không và người dùng
truy cập các thuộc tính này hoặc ghi lại các giá trị của chúng như một phần của bản ghi
mô phỏng?

Tài liệu chi tiết về các thuộc tính thực tế được xác định cho một loại và danh sách chung về
tất cả các thuộc tính được xác định đều có sẵn trong tài liệu API. Đối với phần còn lại của điều này
tài liệu chúng tôi sẽ trình bày các cách khác nhau để lấy và thiết lập thuộc tính
các giá trị.

Giàn cảnh Mặc định Các giá trị
Cấu hình::SetDefault Dòng lệnh
Hãy xem cách tập lệnh người dùng có thể truy cập vào một giá trị thuộc tính cụ thể. Sắp tới
sử dụng src/point-to-point/examples/main-attribute-value.cc kịch bản để minh họa, với
một số chi tiết bị lược bỏ Các chính chức năng bắt đầu:

// Đây là ví dụ cơ bản về cách sử dụng hệ thống thuộc tính để
// đặt và nhận một giá trị trong hệ thống cơ bản; cụ thể là không dấu
// số nguyên của số gói tối đa trong hàng đợi
//

int
main (int argc, char * argv [])
{

// Theo mặc định, thuộc tính MaxPackets có giá trị là 100 gói
// (mặc định này có thể được quan sát thấy trong hàm DropTailQueue::GetTypeId)
//
// Ở đây, chúng tôi đặt thành 80 gói. Chúng ta có thể sử dụng một trong hai loại giá trị:
// giá trị dựa trên chuỗi hoặc giá trị Uinteger
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("80"));
// Lệnh gọi hàm dưới đây là dư thừa
Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (80));

// Cho phép người dùng ghi đè bất kỳ giá trị mặc định nào và ở trên
// SetDefaults () tại thời gian chạy, thông qua đối số dòng lệnh
// Ví dụ: thông qua "--ns3::DropTailQueue::MaxPackets=80"
Dòng lệnh cmd;
// Điều này cung cấp một cách khác để đặt giá trị từ dòng lệnh:
cmd.AddValue ("maxPackets", "ns3::DropTailQueue::MaxPackets");
cmd.Parse(argc, argv);

Điều chính cần chú ý ở trên là hai lệnh gọi tương đương tới Cấu hình::SetDefault
(). Đây là cách chúng tôi đặt giá trị mặc định cho tất cả các phiên bản sau đó
ThảĐuôiHàng ĐợiS. Chúng tôi minh họa rằng hai loại Giá trị lớp học, một Chuỗi giá trị
Giá trị Uinteger lớp, có thể được sử dụng để gán giá trị cho thuộc tính được đặt tên bởi
"ns3::DropTailQueue::MaxPackets".

Cũng có thể thao tác Thuộc tính bằng cách sử dụng Dòng lệnh; chúng tôi đã thấy một số ví dụ
sớm trong phần Hướng dẫn. Đặc biệt, thật đơn giản để thêm một đối số tốc ký
tên, chẳng hạn như --maxGói, đối với Thuộc tính có liên quan cụ thể cho mô hình của bạn,
trong trường hợp này "ns3::DropTailQueue::MaxPackets". Điều này có một tính năng bổ sung là
chuỗi trợ giúp cho Thuộc tính sẽ được in như một phần của thông báo sử dụng cho tập lệnh.
Để biết thêm thông tin xem Dòng lệnh Tài liệu API.

Bây giờ, chúng ta sẽ tạo một vài đối tượng bằng API cấp thấp. Hàng đợi mới được tạo của chúng tôi sẽ
không có m_maxGói được khởi tạo thành 100 gói, như được xác định trong
DropTailQueue::GetTypeId () nhưng tới 80 gói, vì những gì chúng tôi đã làm ở trên với
giá trị mặc định.:

Ptr n0 = CreateObject ();

Ptr net0 = CreateObject ();
n0->AddDevice (net0);

Ptr q = CreateObject ();
net0->AddQueue(q);

Tại thời điểm này, chúng tôi đã tạo một Node (n0) và một đơn PointToPointNetThiết bị
(net0) và thêm một ThảĐuôiHàng Đợi (q) Để net0.

Nhà xây dựng, Người giúp việc Đối tượngNhà máy
Sự kết hợp tùy ý của các thuộc tính có thể được thiết lập và tìm nạp từ trình trợ giúp và cấp thấp
API; hoặc từ chính các nhà xây dựng:

Ptr p =
CreateObjectWithAttribution
("MinX", DoubleValue (-100.0),
"MinY", DoubleValue (-100.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
"LayoutType", StringValue ("RowFirst"));

hoặc từ các API trợ giúp cấp cao hơn, chẳng hạn như:

tính di động.SetPositionAllocator
("ns3::GridPositionAllocator",
"MinX", DoubleValue (-100.0),
"MinY", DoubleValue (-100.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
"LayoutType", StringValue ("RowFirst"));

Chúng tôi không minh họa nó ở đây, nhưng bạn cũng có thể cấu hình một Đối tượngNhà máy với những giá trị mới
cho các thuộc tính cụ thể. Các trường hợp được tạo bởi Đối tượngNhà máy sẽ có những thứ đó
thuộc tính được thiết lập trong quá trình xây dựng. Điều này rất giống với việc sử dụng một trong các API trợ giúp
cho lớp học.

Để xem lại, có một số cách để đặt giá trị cho thuộc tính cho các thể hiện của lớp đến be
tạo ra in các Tương lai:

· Cấu hình::SetDefault ()

· Dòng lệnh::AddValue ()

· CreateObjectWithAttribut<> ()

· Các API trợ giúp khác nhau

Nhưng nếu bạn đã tạo một phiên bản rồi và muốn thay đổi giá trị của
thuộc tính? Trong ví dụ này, làm thế nào chúng ta có thể thao tác m_maxGói giá trị của đã có
tạo ra ThảĐuôiHàng Đợi? Dưới đây là nhiều cách khác nhau để làm điều đó.

Thay đổi Các giá trị
con trỏ thông minh
Giả sử rằng một con trỏ thông minh (ptr) đến thiết bị mạng liên quan đang có trong tay; bây giờ
ví dụ, đó là net0 con trỏ.

Một cách để thay đổi giá trị là truy cập một con trỏ tới hàng đợi cơ bản và sửa đổi nó
thuộc tính.

Đầu tiên, chúng ta quan sát thấy rằng chúng ta có thể lấy một con trỏ tới (lớp cơ sở) Hàng đợi thông qua các
PointToPointNetThiết bị thuộc tính, nơi nó được gọi "TxQueue":

Giá trị con trỏ tmp;
net0->GetAttribution ("TxQueue", tmp);
Ptr txQueue = tmp.GetObject ();

Sử dụng Nhận đối tượng () chức năng, chúng ta có thể thực hiện downcast an toàn tới một ThảĐuôiHàng Đợi, Nơi
"Gói tối đa" là một thuộc tính:

Ptr dtq = txQueue->GetObject ();
NS_ASSERT (dtq != 0);

Tiếp theo, chúng ta có thể lấy giá trị của một thuộc tính trên hàng đợi này. Chúng tôi đã giới thiệu trình bao bọc
Giá trị các lớp dành cho các kiểu dữ liệu cơ bản, tương tự như các trình bao bọc Java xung quanh các kiểu này,
vì hệ thống thuộc tính lưu trữ các giá trị được tuần tự hóa thành chuỗi chứ không phải các loại khác nhau.
Ở đây, giá trị thuộc tính được gán cho một Giá trị Uinteger, và Nhận () phương pháp này
giá trị tạo ra (chưa được mở) uint32_t.:

Giới hạn UintegerValue;
dtq->GetAttribution ("MaxPackets", giới hạn);
NS_LOG_INFO ("giới hạn 1. dtq: " << limit.Get () << " gói");

Lưu ý rằng downcast ở trên là không thực sự cần thiết; chúng ta có thể có được thuộc tính
giá trị trực tiếp từ txQueue, đó là một Đối tượng:

txQueue->GetAttribution ("MaxPackets", giới hạn);
NS_LOG_INFO ("giới hạn 2. txQueue: " << limit.Get () << " gói");

Bây giờ, hãy đặt nó thành giá trị khác (60 gói):

txQueue->SetAttribution("MaxPackets", UintegerValue (60));
txQueue->GetAttribution ("MaxPackets", giới hạn);
NS_LOG_INFO ("3. giới hạn txQueue đã thay đổi: " << limit.Get () << " gói");

Config Không gian tên Đường dẫn
Một cách khác để lấy thuộc tính là sử dụng không gian tên cấu hình. Đây,
thuộc tính này nằm trên một đường dẫn đã biết trong không gian tên này; Cách tiếp cận này hữu ích nếu một
không có quyền truy cập vào các con trỏ cơ bản và muốn định cấu hình một con trỏ cụ thể
thuộc tính với một câu lệnh duy nhất.:

Cấu hình::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets",
UintegerValue (25));
txQueue->GetAttribution ("MaxPackets", giới hạn);
NS_LOG_INFO ("Giới hạn 4. txQueue đã thay đổi thông qua không gian tên: "
<< limit.Get () << " gói");

Đường dẫn cấu hình thường có dạng ".../
tên>/ /.../ / " để đề cập đến một trường hợp cụ thể theo chỉ mục của một
vật trong thùng chứa. Trong trường hợp này vùng chứa đầu tiên là danh sách tất cả NodeS; các
container thứ hai là danh sách tất cả thiết bị mạngs trên lựa chọn Node. cuối cùng
đường dẫn cấu hình thường kết thúc bằng một chuỗi các thuộc tính thành viên, trong trường hợp này là
"Gói tối đa" thuộc tính của "TxQueue" của người được chọn thiết bị mạng.

Chúng tôi cũng có thể sử dụng ký tự đại diện để đặt giá trị này cho tất cả các nút và tất cả thiết bị mạng
(trong ví dụ đơn giản này có tác dụng tương tự như ví dụ trước Cấu hình :: Đặt ()):

Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets",
UintegerValue (15));
txQueue->GetAttribution ("MaxPackets", giới hạn);
NS_LOG_INFO ("Giới hạn 5. txQueue đã thay đổi thông qua vùng tên có ký tự đại diện: "
<< limit.Get () << " gói");

Đối tượng Họ tên Dịch vụ
Một cách khác để lấy thuộc tính là sử dụng tiện ích dịch vụ tên đối tượng. Các
dịch vụ tên đối tượng cho phép chúng ta thêm các mục vào không gian tên cấu hình trong phần
"/Tên/" đường dẫn có chuỗi tên do người dùng xác định. Cách tiếp cận này rất hữu ích nếu người ta không
có quyền truy cập vào các con trỏ cơ bản và rất khó để xác định yêu cầu
đường dẫn không gian tên cấu hình cụ thể.

Tên::Thêm ("máy chủ", n0);
Tên::Thêm ("server/eth0", net0);

...

Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));

Ở đây chúng tôi đã thêm các thành phần đường dẫn "máy chủ""eth0" theo "/Tên/" không gian tên, sau đó
đã sử dụng đường dẫn cấu hình kết quả để đặt thuộc tính.

Xem Tên đối tượng để biết cách xử lý đầy đủ hơn về ns-3 không gian tên cấu hình.

Triển khai hệ thống Chi Tiết
Giá trị Các lớp học
Người đọc sẽ lưu ý LoạiGiá trị các lớp là các lớp con của Giá trị thuộc tính cơ sở
lớp học. Đây có thể được coi là các lớp trung gian được sử dụng để chuyển đổi từ dạng thô
các loại để Giá trị thuộc tínhs được sử dụng bởi hệ thống thuộc tính. Hãy nhớ lại rằng điều này
cơ sở dữ liệu đang chứa các đối tượng thuộc nhiều loại được tuần tự hóa thành chuỗi. Chuyển đổi sang loại này
có thể được thực hiện bằng cách sử dụng một lớp trung gian (chẳng hạn như Giá trị số nguyên, hoặc là Giá trị gấp đôi cho
số dấu phẩy động) hoặc thông qua dây. Chuyển đổi ngầm định trực tiếp các loại thành
Giá trị thuộc tính không thực sự thiết thực. Vì vậy ở phần trên người dùng có quyền lựa chọn sử dụng
chuỗi hoặc giá trị:

p->Set ("cwnd", StringValue ("100")); // setter dựa trên chuỗi
p->Set ("cwnd", IntegerValue (100)); // setter dựa trên số nguyên

Hệ thống cung cấp một số macro giúp người dùng khai báo, xác định AttributionValue mới
các lớp con cho các kiểu mới mà họ muốn đưa vào hệ thống thuộc tính:

· ATTRIBUTE_HELPER_HEADER

· ATTRIBUTE_HELPER_CPP

Xem tài liệu API cho các cấu trúc này để biết thêm thông tin.

Khởi tạo Mã đơn hàng
Các thuộc tính trong hệ thống không được phụ thuộc vào trạng thái của bất kỳ Thuộc tính nào khác trong hệ thống này
hệ thống. Điều này là do thứ tự khởi tạo Thuộc tính không được chỉ định, cũng như không
được thực thi bởi hệ thống. Một ví dụ cụ thể về điều này có thể được nhìn thấy trong cấu hình tự động
các chương trình như Cửa hàng cấu hình. Mặc dù một mô hình nhất định có thể sắp xếp nó sao cho Thuộc tính
được khởi tạo theo một thứ tự cụ thể, một bộ cấu hình tự động khác có thể quyết định
một cách độc lập để thay đổi các Thuộc tính theo thứ tự chữ cái, ví dụ.

Do thứ tự không cụ thể này nên không có Thuộc tính nào trong hệ thống có thể có bất kỳ sự phụ thuộc nào
trên bất kỳ Thuộc tính nào khác. Như một hệ quả tất yếu, các trình thiết lập thuộc tính không bao giờ được thất bại do trạng thái
của Thuộc tính khác. Không có bộ thiết lập thuộc tính nào có thể thay đổi (đặt) bất kỳ giá trị Thuộc tính nào khác dưới dạng
kết quả của việc thay đổi giá trị của nó.

Đây là một hạn chế rất mạnh và có trường hợp phải đặt Thuộc tính
nhất quán để cho phép hoạt động chính xác. Để đạt được mục đích này, chúng tôi cho phép kiểm tra tính nhất quán
khi nào các thuộc tính is đã sử dụng (cf. NS_ASSERT_MSG or NS_ABORT_MSG).

Nói chung, mã thuộc tính để gán giá trị cho các biến thành viên của lớp cơ bản
được thực thi sau khi một đối tượng được xây dựng. Nhưng nếu bạn cần các giá trị được gán
trước khi phần thân hàm tạo thực thi, bởi vì bạn cần chúng theo logic của
người xây dựng? Có một cách để làm điều này, ví dụ được sử dụng trong lớp Cửa hàng cấu hình: gọi
ObjectBase::ConstructSelf () như sau:

ConfigStore::ConfigStore ()
{
ObjectBase::ConstructSelf (AttributionConstructionList ());
// tiếp tục với hàm tạo.
}

Hãy lưu ý rằng đối tượng và tất cả các lớp dẫn xuất của nó cũng phải thực hiện một GetInstanceTypeId
() phương pháp. Nếu không ObjectBase::ConstructSelf () sẽ không thể đọc được
thuộc tính.

Thêm Thuộc tính
ns-3 hệ thống sẽ đặt một số giá trị nội bộ dưới hệ thống thuộc tính, nhưng
chắc chắn người dùng sẽ muốn mở rộng điều này để chọn những cái chúng tôi đã bỏ lỡ hoặc để thêm
các lớp riêng của mình vào hệ thống.

Có ba trường hợp sử dụng điển hình:

· Làm cho một thành viên dữ liệu lớp hiện có có thể truy cập được dưới dạng Thuộc tính, khi chưa có.

· Tạo một lớp mới có thể hiển thị một số thành viên dữ liệu dưới dạng Thuộc tính bằng cách cấp cho nó TypeId.

· Tạo một Giá trị thuộc tính lớp con cho một lớp mới để nó có thể được truy cập như một lớp
Thuộc tính.

Hiện tại Thành viên Biến
Hãy xem xét biến này trong Ổ cắm Tcp:

uint32_t m_cWnd; // Cửa sổ tắc nghẽn

Giả sử ai đó làm việc với TCP muốn lấy hoặc đặt giá trị của biến đó
sử dụng hệ thống siêu dữ liệu. Nếu nó chưa được cung cấp bởi ns-3, người dùng có thể khai báo
phần bổ sung sau đây trong hệ thống siêu dữ liệu thời gian chạy (vào GetTypeId() định nghĩa cho
Ổ cắm Tcp):

.AddAttribution ("Cửa sổ tắc nghẽn",
"Cửa sổ tắc nghẽn Tcp (byte)",
UintegerValue (1),
MakeUintegerAccessor (&TcpSocket::m_cWnd),
MakeUintegerChecker ())

Bây giờ, người dùng có con trỏ tới một Ổ cắm Tcp instance có thể thực hiện các hoạt động như
thiết lập và nhận giá trị mà không cần phải thêm các hàm này một cách rõ ràng.
Hơn nữa, có thể áp dụng các biện pháp kiểm soát truy cập, chẳng hạn như cho phép đọc và
không được viết hoặc có thể áp dụng việc kiểm tra giới hạn các giá trị cho phép.

Mới Lớp loạiId
Ở đây, chúng tôi thảo luận về tác động đối với người dùng muốn thêm một lớp mới vào ns-3. Gì
những điều bổ sung phải được thực hiện để cho phép nó giữ các thuộc tính?

Giả sử lớp mới của chúng ta, được gọi là ns3::MyMobility, là một loại mô hình di động. Đầu tiên,
lớp nên kế thừa từ lớp cha của nó, ns3 :: MobilityModel. Trong my-mobile.h
tập tin tiêu đề:

không gian tên ns3 {

lớp MyClass : MobilityModel công khai
{

Điều này đòi hỏi chúng ta phải khai báo GetTypeId () chức năng. Đây là một chức năng công cộng một dòng
tuyên ngôn:

công khai:
/ **
* Đăng ký loại này.
* \return Đối tượng TypeId.
*/
TypeId tĩnh GetTypeId (void);

Chúng tôi đã giới thiệu những gì loạiId định nghĩa sẽ giống như trong my-mobile.cc
tập tin thực hiện:

NS_OBJECT_ENSURE_REGISTERED (MyMobility);

loạiId
MyMobility::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::MyMobility")
.SetParent ()
.SetGroupName ("Tính di động")
.AddConstructor ()
.AddAttribution ("Giới hạn",
"Giới hạn của khu vực để đi du thuyền.",
RectangleValue (Hình chữ nhật (0.0, 0.0, 100.0, 100.0)),
MakeRectangleAccessor (&MyMobility::m_bounds),
MakeRectangleChecker ())
.AddAttribution ("Thời gian",
"Thay đổi hướng và tốc độ hiện tại sau khi di chuyển trong thời gian trễ này.",
Giá trị thời gian (Giây (1.0)),
MakeTimeAccessor (&MyMobility::m_modeTime),
MakeTimeChecker ())
// vv (thêm tham số).
;
trả lại tid;
}

Nếu chúng ta không muốn phân lớp từ một lớp hiện có, trong tệp tiêu đề chúng ta chỉ kế thừa
từ ns3 :: Đối tượngvà trong tệp đối tượng, chúng tôi đặt lớp cha thành ns3 :: Đối tượng với
.SetParent ().

Những sai lầm điển hình ở đây bao gồm:

· Không gọi NS_OBJECT_ENSURE_REGISTERED ()

· Không gọi điện SetParent () phương thức hoặc gọi nó sai kiểu.

· Không gọi điện AddConstructor () phương thức hoặc gọi nó sai kiểu.

· Giới thiệu lỗi đánh máy trong tên của loạiId trong hàm tạo của nó.

· Không sử dụng tên kiểu C++ đủ tiêu chuẩn của lớp C++ kèm theo làm tên của
loạiId. Lưu ý rằng "ns3::" bắt buộc.

Không có lỗi nào trong số này có thể được phát hiện bởi ns-3 codebase, vì vậy người dùng nên kiểm tra
cẩn thận nhiều lần để họ làm đúng.

Mới Giá trị thuộc tính Kiểu
Từ góc độ của người dùng viết một lớp mới trong hệ thống và muốn nó được
có thể truy cập như một thuộc tính, vấn đề chủ yếu là ghi các chuyển đổi đến/từ
chuỗi và giá trị thuộc tính. Hầu hết điều này có thể được sao chép/dán bằng mã macro. Vì
Ví dụ, hãy xem xét một khai báo lớp cho Hình chữ nhật trong src/tính di động/mô hình danh mục:

Tiêu đề Tập tin
/ **
* \tóm tắt một hình chữ nhật 2d
*/
lớp Hình chữ nhật
{
...

gấp đôi xMin;
xMax gấp đôi;
yMin gấp đôi;
yMax gấp đôi;
};

Một lệnh gọi macro và hai toán tử phải được thêm vào bên dưới phần khai báo lớp để
biến Hình chữ nhật thành một giá trị có thể sử dụng được bởi đặc tính hệ thống:

std::ostream &operator << (std::ostream &os, const Hình chữ nhật &hình chữ nhật);
std::istream &operator >> (std::istream &is, Hình chữ nhật &hình chữ nhật);

ATTRIBUTE_HELPER_HEADER (Hình chữ nhật);

Triển khai hệ thống Tập tin
Trong định nghĩa lớp (. Cc tập tin), mã trông như thế này:

ATTRIBUTE_HELPER_CPP (Hình chữ nhật);

std::ostream &
toán tử << (std::ostream &os, const Hình chữ nhật &hình chữ nhật)
{
os << hình chữ nhật.xMin << "|" << hình chữ nhật.xMax << "|" << hình chữ nhật.yMin << "|"
<< hình chữ nhật.yMax;
trả lại hệ điều hành;
}
std::istream &
toán tử >> (std::istream &is, Hình chữ nhật &hình chữ nhật)
{
ký tự c1, c2, c3;
là >> hình chữ nhật.xMin >> c1 >> hình chữ nhật.xMax >> c2 >> hình chữ nhật.yMin >> c3
>> hình chữ nhật.yMax;
nếu (c1 != '|' ||
c2 != '|' ||
c3 != '|')
{
is.setstate (std::ios_base::failbit);
}
trở lại là;
}

Các toán tử luồng này chỉ cần chuyển đổi từ biểu diễn chuỗi của Hình chữ nhật
("xMin|xMax|yMin|yMax") vào Hình chữ nhật bên dưới. Người lập mô hình phải chỉ rõ những điều này
các toán tử và biểu diễn cú pháp chuỗi của một thể hiện của lớp mới.

Cửa hàng cấu hình
Giá trị cho ns-3 các thuộc tính có thể được lưu trữ trong tệp văn bản ASCII hoặc XML và được tải vào một
chạy mô phỏng trong tương lai. Tính năng này được gọi là ns-3 ConfigStore. Các Cửa hàng cấu hình is
một cơ sở dữ liệu chuyên dụng cho các giá trị thuộc tính và giá trị mặc định.

Mặc dù nó là một mô-đun được duy trì riêng biệt trong src/config-store/ thư mục, chúng tôi
ghi lại nó ở đây vì sự phụ thuộc duy nhất của nó vào ns-3 mô-đun cốt lõi và các thuộc tính.

Chúng ta có thể khám phá hệ thống này bằng cách sử dụng một ví dụ từ
src/config-store/examples/config-store-save.cc.

Đầu tiên, tất cả người dùng của Cửa hàng cấu hình phải bao gồm tuyên bố sau:

#include "ns3/config-store-module.h"

Tiếp theo, chương trình này thêm một đối tượng mẫu Cấu hìnhVí dụ để chỉ ra cách hệ thống được mở rộng:

lớp ConfigExample: Đối tượng công cộng
{
công khai:
TypeId tĩnh GetTypeId (void) {
static TypeId tid = TypeId ("ns3::A")
.SetParent ()
.AddAttribution ("TestInt16", "văn bản trợ giúp",
Giá trị nguyên (-2),
MakeIntegerAccessor (&A::m_int16),
MakeIntegerChecker ())
;
trả lại tid;
}
int16_t m_int16;
};

NS_OBJECT_ENSURE_REGISTERED (Ví dụ về cấu hình);

Tiếp theo, chúng tôi sử dụng hệ thống con Cấu hình để ghi đè các giá trị mặc định theo một số cách:

Config::SetDefault ("ns3::ConfigExample::TestInt16", IntegerValue (-5));

Ptr a_obj = Tạo đối tượng ();
NS_ABORT_MSG_UNLESS (a_obj->m_int16 == -5,
"Không thể đặt thuộc tính số nguyên của ConfigExample thông qua Config::SetDefault");

Ptr a2_obj = Tạo đối tượng ();
a2_obj->SetAttribution ("TestInt16", IntegerValue (-3));
Giá trị nguyên iv;
a2_obj->GetAttribution ("TestInt16", iv);
NS_ABORT_MSG_UNLESS (iv.Get() == -3,
"Không thể đặt thuộc tính số nguyên của ConfigExample thông qua SetAttribution");

Câu lệnh tiếp theo là cần thiết để đảm bảo rằng (một trong) đối tượng được tạo đã được root
trong không gian tên cấu hình dưới dạng một thể hiện đối tượng. Điều này thường xảy ra khi bạn
tổng hợp các đối tượng thành một ns3 :: Node or ns3::Kênh ví dụ, nhưng ở đây, vì chúng tôi đang làm việc
ở cấp độ cốt lõi, chúng ta cần tạo một đối tượng không gian tên gốc mới:

Cấu hình::RegisterRootNamespaceObject (a2_obj);

Writing
Tiếp theo, chúng tôi muốn xuất kho cấu hình. Các ví dụ cho thấy cách thực hiện điều đó trong hai
định dạng, XML và văn bản thô. Trong thực tế, người ta nên thực hiện bước này ngay trước khi gọi
Trình mô phỏng :: Chạy () để lưu cấu hình cuối cùng ngay trước khi chạy mô phỏng.

Có ba Thuộc tính chi phối hoạt động của ConfigStore: "Cách thức",
"Tên tập tin""Định dạng tệp". Chế độ (mặc định "Không có") cấu hình xem ns-3 nên
tải cấu hình từ một tệp đã lưu trước đó (chỉ định "Chế độ=Tải") hoặc lưu nó vào một tập tin
(ghi rõ "Chế độ=Lưu"). Tên tệp (mặc định "") là nơi ConfigStore sẽ đọc hoặc
ghi dữ liệu của nó. FileFormat (mặc định "Văn bản thô") chi phối việc định dạng ConfigStore
là văn bản thuần túy hoặc Xml ("Định dạng tệp=Xml")

Ví dụ cho thấy:

Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
ConfigStore đầu raConfig;
outConfig.ConfigureDefaults ();
outConfig.ConfigureAttribut ();

// Xuất cấu hình lưu trữ sang định dạng txt
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.txt"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("RawText"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
ConfigStore đầu raConfig2;
outConfig2.ConfigureDefaults ();
outConfig2.ConfigureAttribut ();

Trình mô phỏng :: Run ();

Trình mô phỏng :: Phá hủy ();

Lưu ý vị trí của các tuyên bố này ngay trước Trình mô phỏng :: Chạy () tuyên bố.
Đầu ra này ghi lại tất cả các giá trị tại chỗ ngay trước khi bắt đầu mô phỏng (tức là.
sau khi tất cả quá trình cấu hình đã diễn ra).

Sau khi chạy, bạn có thể mở thuộc tính đầu ra.txt tập tin và xem:

mặc định ns3::RealtimeSimulatorImpl::SynchronizationMode "BestEffort"
mặc định ns3::RealtimeSimulatorImpl::HardLimit "+100000000.0ns"
mặc định ns3::PcapFileWrapper::CaptureSize "65535"
mặc định ns3::PacketSocket::RcvBufSize "131072"
mặc định ns3::ErrorModel::IsEnabled "true"
mặc định ns3::RateErrorModel::ErrorUnit "EU_BYTE"
mặc định ns3::RateErrorModel::ErrorRate "0"
mặc định ns3::RateErrorModel::RanVar "Đồng phục:0:1"
mặc định ns3::DropTailQueue::Chế độ "Gói"
mặc định ns3::DropTailQueue::MaxPackets "100"
mặc định ns3::DropTailQueue::MaxBytes "6553500"
mặc định ns3::Application::StartTime "+0.0ns"
mặc định ns3::Application::StopTime "+0.0ns"
mặc định ns3::ConfigStore::Chế độ "Lưu"
mặc định ns3::ConfigStore::Tên tệp "output-attributes.txt"
mặc định ns3::ConfigStore::FileFormat "RawText"
mặc định ns3::ConfigExample::TestInt16 "-5"
RngSeed toàn cầu "1"
RngRun toàn cầu "1"
SimulatorImplementationType toàn cầu "ns3::DefaultSimulatorImpl"
Bộ lập lịch toàn cầuType "ns3::MapScheduler"
Tổng kiểm tra toàn cầu được bật "false"
giá trị /$ns3::ConfigExample/TestInt16 "-3"

Ở phần trên, tất cả các giá trị mặc định cho thuộc tính của mô-đun lõi đều được hiển thị.
Khi đó, tất cả các giá trị của ns-3 giá trị toàn cầu được ghi lại. Cuối cùng, giá trị của
ví dụ của Cấu hìnhVí dụ đã được root trong không gian tên cấu hình được hiển thị. trong một
thực ns-3 chương trình, nhiều mô hình, thuộc tính và giá trị mặc định khác sẽ được hiển thị.

Một phiên bản XML cũng tồn tại trong thuộc tính đầu ra.xml:




























Tệp này có thể được lưu trữ cùng với tập lệnh mô phỏng và dữ liệu đầu ra của bạn.

Reading
Tiếp theo, chúng ta thảo luận về việc định cấu hình mô phỏng thông qua một tập tin cấu hình đầu vào được lưu trữ. Có
một vài điểm khác biệt chính so với việc viết cấu hình mô phỏng cuối cùng.
Đầu tiên, chúng ta cần đặt các câu lệnh như thế này ở đầu chương trình, trước
các câu lệnh cấu hình mô phỏng được viết (vì vậy các giá trị được đăng ký trước khi
được sử dụng trong xây dựng đối tượng).

Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults();

Tiếp theo, lưu ý rằng việc tải dữ liệu cấu hình đầu vào bị giới hạn ở Thuộc tính mặc định (tức là.
không phải giá trị instance) và giá trị chung. Giá trị phiên bản thuộc tính không được hỗ trợ
bởi vì ở giai đoạn mô phỏng này, trước khi xây dựng bất kỳ đối tượng nào, không có
các trường hợp đối tượng như vậy xung quanh. (Lưu ý, những cải tiến trong tương lai đối với kho cấu hình có thể thay đổi
hành vi này).

Thứ hai, trong khi đầu ra của Cửa hàng cấu hình state sẽ liệt kê mọi thứ trong cơ sở dữ liệu,
tệp đầu vào chỉ cần chứa các giá trị cụ thể sẽ được ghi đè. Vì vậy, một cách để sử dụng
Lớp cấu hình tệp đầu vào này nhằm tạo cấu hình ban đầu bằng cách sử dụng
đầu ra ("Cứu") "Cách thức" được mô tả ở trên, chỉ trích xuất từ ​​tệp cấu hình đó
các phần tử muốn thay đổi và di chuyển các phần tử tối thiểu này sang tệp cấu hình mới
sau đó có thể được chỉnh sửa và tải một cách an toàn trong lần chạy mô phỏng tiếp theo.

Khi Cửa hàng cấu hình đối tượng được khởi tạo, các thuộc tính của nó "Tên tập tin", "Cách thức"
"Định dạng tệp" phải được thiết lập thông qua dòng lệnh hoặc thông qua phát biểu của chương trình.

Đọc viết Ví dụ
Như một ví dụ phức tạp hơn, giả sử rằng chúng ta muốn đọc trong cấu hình
mặc định từ một tệp đầu vào có tên đầu vào-defaults.xml, và viết kết quả
thuộc tính cho một tệp riêng biệt gọi là thuộc tính đầu ra.xml.:

#include "ns3/config-store-module.h"
...
int chính (...)
{

Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults();

//
// Cho phép người dùng ghi đè bất kỳ giá trị mặc định nào và Bind() ở trên tại
// đối số thời gian chạy, thông qua dòng lệnh
//
Dòng lệnh cmd;
cmd.Parse(argc, argv);

// thiết lập cấu trúc liên kết
...

// Gọi ngay trước khi vào Simulator::Run ()
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
ConfigStore đầu raConfig;
outConfig.ConfigureAttribut ();
Trình mô phỏng :: Run ();
}

Cửa hàng cấu hình GUI
Có giao diện người dùng dựa trên GTK cho ConfigStore. Điều này cho phép người dùng sử dụng GUI để
truy cập và thay đổi các biến. Ảnh chụp màn hình của tính năng này có sẵn trong |ns3|
Giới thiệu chung trình bày.

Để sử dụng tính năng này, người ta phải cài đặt libgtklibgtk-dev; một ví dụ về Ubuntu
lệnh cài đặt là:

$ sudo apt-get cài đặt libgtk2.0-0 libgtk2.0-dev

Để kiểm tra xem nó đã được cấu hình hay chưa, hãy kiểm tra đầu ra của bước:

$ ./waf config --enable -amples --enable-tests

---- Tóm tắt các tính năng NS-3 tùy chọn:
Python Bindings: đã bật
Hỗ trợ quét API Python: đã bật
Tích hợp nhấp chuột NS-3 : đã bật
GtkConfigStore: chưa được bật (không tìm thấy thư viện 'gtk+-2.0 >= 2.12')

Trong ví dụ trên, nó chưa được kích hoạt nên không thể sử dụng cho đến khi có phiên bản phù hợp.
đã cài đặt và:

$ ./waf config --enable -amples --enable-tests
$ ./waf

đang chạy lại.

Cách sử dụng gần giống như phiên bản không dựa trên GTK, nhưng không có Cửa hàng cấu hình
thuộc tính liên quan:

// Gọi ngay trước khi vào Simulator::Run ()
Cấu hình GtkConfigStore;
config.ConfigureDefaults ();
config.ConfigureAttribut ();

Bây giờ, khi bạn chạy tập lệnh, một GUI sẽ bật lên, cho phép bạn mở các menu của
thuộc tính trên các nút/đối tượng khác nhau, sau đó khởi chạy thực thi mô phỏng khi bạn
được thực hiện.

Tương lai công việc
Có một số cải tiến có thể có:

· Lưu số phiên bản duy nhất kèm theo ngày và giờ khi bắt đầu tập tin.

· Lưu hạt giống ban đầu ở đâu đó.

· Làm cho mỗi RandomVariable tuần tự hóa hạt giống ban đầu của chính nó và đọc lại nó sau.

Đối tượng tên
Placeholder chương

Logging
ns-3 cơ sở ghi nhật ký có thể được sử dụng để theo dõi hoặc gỡ lỗi tiến trình mô phỏng
các chương trình. Đầu ra ghi nhật ký có thể được kích hoạt bằng các câu lệnh chương trình trong chủ yếu() chương trình hay
bằng cách sử dụng NS_LOG biến môi trường.

Báo cáo ghi nhật ký không được biên dịch thành các bản dựng được tối ưu hóa của ns-3. Để sử dụng tính năng ghi nhật ký, một
phải xây dựng bản dựng gỡ lỗi (mặc định) của ns-3.

Dự án không đảm bảo về việc liệu sản lượng ghi nhật ký có giữ nguyên trong suốt thời gian hay không
thời gian. Người dùng được cảnh báo không nên xây dựng khung đầu ra mô phỏng khi ghi nhật ký
mã, vì đầu ra và cách kích hoạt đầu ra có thể thay đổi theo thời gian.

Giới thiệu chung
ns-3 câu lệnh ghi nhật ký thường được sử dụng để ghi nhật ký các sự kiện thực thi chương trình khác nhau, chẳng hạn như
như sự xuất hiện của các sự kiện mô phỏng hoặc việc sử dụng một chức năng cụ thể.

Ví dụ: đoạn mã này là từ Ipv4L3Protocol::IsDestinationAddress():

if (địa chỉ == iaddr.GetBroadcast ())
{
NS_LOG_LOGIC ("Đối với tôi (địa chỉ quảng bá giao diện)");
return true;
}

Nếu tính năng ghi nhật ký đã được bật cho Giao thức Ipv4L3 thành phần ở mức độ nghiêm trọng của LOGIC or
ở trên (xem bên dưới về mức độ nghiêm trọng của nhật ký), tuyên bố sẽ được in ra; nếu không thì nó
sẽ bị đàn áp.

Cho phép Đầu ra
Có hai cách mà người dùng thường kiểm soát đầu ra nhật ký. Đầu tiên là bằng cách thiết lập
NS_LOG biến môi trường; ví dụ:

$ NS_LOG="*" ./waf --chạy trước

sẽ chạy Thành phố điện khí hóa phía tây dãy núi Rocky đầu tiên chương trình hướng dẫn với tất cả đầu ra ghi nhật ký. (Các chi tiết cụ thể của NS_LOG
định dạng sẽ được thảo luận dưới đây.)

Điều này có thể được thực hiện chi tiết hơn bằng cách chọn các thành phần riêng lẻ:

$ NS_LOG="Ipv4L3Protocol" ./waf --chạy trước

Đầu ra có thể được điều chỉnh thêm với các tùy chọn tiền tố.

Cách thứ hai để kích hoạt tính năng ghi nhật ký là sử dụng các câu lệnh rõ ràng trong chương trình của bạn, chẳng hạn như trong
các Thành phố điện khí hóa phía tây dãy núi Rocky đầu tiên chương trình hướng dẫn:

int
main (int argc, char * argv [])
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("Ứng dụng UdpEchoServer", LOG_LEVEL_INFO);
...

(Nghĩa của LOG_LEVEL_INFOvà các giá trị có thể khác sẽ được thảo luận bên dưới.)

NS_LOG cú pháp
NS_LOG biến môi trường chứa danh sách các thành phần và tùy chọn nhật ký. Nhật ký
các thành phần được phân tách bằng ký tự `:':

$ NS_LOG=" : ..."

Các tùy chọn cho từng thành phần nhật ký được cung cấp dưới dạng cờ sau mỗi thành phần nhật ký:

$ NS_LOG=" = | ...: ..."

Các tùy chọn kiểm soát mức độ nghiêm trọng và mức độ của thành phần đó và liệu tùy chọn có
thông tin cần được đưa vào, chẳng hạn như thời gian mô phỏng, nút mô phỏng, chức năng
tên và mức độ nghiêm trọng mang tính biểu tượng.

Khúc gỗ Linh kiện
Nói chung, một thành phần nhật ký đề cập đến một mã nguồn duy nhất . Cc tập tin và bao gồm
toàn bộ tập tin.

Một số người trợ giúp có các phương thức đặc biệt để cho phép ghi nhật ký tất cả các thành phần trong một mô-đun,
trải rộng trên nhiều đơn vị biên dịch khác nhau nhưng được nhóm lại với nhau một cách hợp lý, chẳng hạn như ns-3
mã wifi:

WifiHelper wifiHelper;
wifiHelper.EnableLogComponents ();

NS_LOG ký tự đại diện thành phần nhật ký `*' sẽ kích hoạt tất cả các thành phần.

Để xem thành phần nhật ký nào được xác định, bất kỳ thành phần nào trong số này sẽ hoạt động:

$ NS_LOG="print-list" ./waf --run ...

$ NS_LOG="foo" # mã thông báo không khớp với bất kỳ thành phần nhật ký nào

Biểu mẫu đầu tiên sẽ in tên và cờ kích hoạt cho tất cả các thành phần nhật ký được
liên kết trong; thử nó với mô phỏng vết xước. Biểu mẫu thứ hai in tất cả nhật ký đã đăng ký
thành phần, sau đó thoát ra với một lỗi.

Mức độ nghiêm trọng Cấp Các lựa chọn
Các thông báo riêng lẻ thuộc về một "lớp mức độ nghiêm trọng" duy nhất do macro tạo ra
tin nhắn. Trong ví dụ trên, NS_LOG_LOGIC(..) tạo thông báo trong LOG_LOGIC
lớp mức độ nghiêm trọng.

Các mức độ nghiêm trọng sau đây được định nghĩa là liệt kê hằng số:

┌───────────────┬──────────────────────── ───────── ─┐
│Cấp độ nghiêm trọng │ Ý nghĩa │
├───────────────┼──────────────────────── ───────── ─┤
LOG_NONE │ Mặc định, không ghi nhật ký │
├───────────────┼──────────────────────── ───────── ─┤
LOG_ERROR │ Chỉ thông báo lỗi nghiêm trọng │
├───────────────┼──────────────────────── ───────── ─┤
LOG_WARN │ Thông báo cảnh báo │
├───────────────┼──────────────────────── ───────── ─┤
LOG_DEBUG │ Để sử dụng trong việc gỡ lỗi │
├───────────────┼──────────────────────── ───────── ─┤
LOG_INFO │ Thông tin │
├───────────────┼──────────────────────── ───────── ─┤
LOG_FUNCTION │ Truy tìm chức năng │
├───────────────┼──────────────────────── ───────── ─┤
LOG_LOGIC │ Kiểm soát việc theo dõi luồng trong │
│ │ chức năng │
└───────────────┴──────────────────────── ───────── ─┘

Thông thường, người ta muốn xem tin nhắn ở mức độ nghiêm trọng nhất định cao hơn. Điều này được thực hiện bởi
xác định "mức" ghi nhật ký bao gồm:

┌───────────────────── ─────┐
│Cấp độ │ Ý nghĩa │
├───────────────────── ─────┤
LOG_LEVEL_ERROR │ Chỉ LOG_ERROR mức độ nghiêm trọng │
│ │ tin nhắn. │
├───────────────────── ─────┤
LOG_LEVEL_WARNLOG_WARN và ở trên. │
├───────────────────── ─────┤
LOG_LEVEL_DEBUGLOG_DEBUG và ở trên. │
├───────────────────── ─────┤
LOG_LEVEL_INFOLOG_INFO và ở trên. │
├───────────────────── ─────┤
LOG_LEVEL_FUNCTIONLOG_FUNCTION và ở trên. │
├───────────────────── ─────┤
LOG_LEVEL_LOGICLOG_LOGIC và ở trên. │
├───────────────────── ─────┤
LOG_LEVEL_ALL │ Tất cả các mức độ nghiêm trọng. │
├───────────────────── ─────┤
LOG_ALL │ Từ đồng nghĩa với LOG_LEVEL_ALL
└───────────────────── ─────┘

Các tùy chọn mức độ và mức độ nghiêm trọng có thể được đưa ra trong NS_LOG biến môi trường bởi
những mã thông báo này:

┌─────────┬────────────────┐
│Lớp │ Cấp │
├─────────┼────────────────┤
lôicấp_lỗi
├─────────┼────────────────┤
cảnh báocấp_cảnh báo
├─────────┼────────────────┤
gỡ lỗicấp_debug
├─────────┼────────────────┤
Thông tincấp_thông tin
├─────────┼────────────────┤
chức năngcấp_chức năng
├─────────┼────────────────┤
logiccấp_logic
├─────────┼────────────────┤
│ │ cấp_tất cả
│ │ tất cả các
│ │ *
└─────────┴────────────────┘

Việc sử dụng mã thông báo cấp mức độ nghiêm trọng chỉ cho phép thông báo nhật ký ở mức độ nghiêm trọng đó. Ví dụ,
NS_LOG="*=cảnh báo" sẽ không xuất ra tin nhắn với mức độ nghiêm trọng lôi. NS_LOG="*=level_debug" sẽ
thông báo đầu ra ở mức độ nghiêm trọng gỡ lỗi và ở trên.

Các lớp và mức độ nghiêm trọng có thể được kết hợp với `|' nhà điều hành:
NS_LOG="*=level_warn|logic" sẽ xuất thông báo ở mức độ nghiêm trọng lôi, cảnh báologic.

NS_LOG ký tự đại diện mức độ nghiêm trọng `*' và tất cả các là từ đồng nghĩa với cấp_tất cả.

Đối với các thành phần nhật ký chỉ được đề cập trong NS_LOG

$ NS_LOG=" :..."

mức độ nghiêm trọng mặc định là LOG_LEVEL_ALL.

Tiếp đầu ngữ Các lựa chọn
Một số tiền tố có thể giúp xác định vị trí và thời điểm thông điệp bắt nguồn và tại thời điểm nào.
mức độ nghiêm trọng.

Các tùy chọn tiền tố có sẵn (như liệt kê hằng số) là

┌─────────────────── ───┐
│Biểu tượng tiền tố │ Ý nghĩa │
├─────────────────── ───┤
LOG_PREFIX_FUNC │ Tiền tố tên của cuộc gọi │
│ │ chức năng. │
├─────────────────── ───┤
LOG_PREFIX_TIME │ Tiền tố thời gian mô phỏng. │
├─────────────────── ───┤
LOG_PREFIX_NODE │ Tiền tố id nút. │
├─────────────────── ───┤
LOG_PREFIX_LEVEL │ Tiền tố mức độ nghiêm trọng. │
├─────────────────── ───┤
LOG_PREFIX_ALL │ Kích hoạt tất cả các tiền tố. │
└─────────────────── ───┘

Các tùy chọn tiền tố được mô tả ngắn gọn bên dưới.

Các tùy chọn có thể được đưa ra trong NS_LOG biến môi trường bằng các mã thông báo này:

┌─────────────┬───────────┐
│Mã thông báo │ Thay thế │
├─────────────┼───────────┤
tiền tố_funcchức năng
├─────────────┼───────────┤
tiền tố_thời gianthời gian
└─────────────┴───────────┘

tiền tố_nodenút
├─────────────┼───────────┤
tiền tố_cấpcấp
├─────────────┼───────────┤
tiền tố_tất cảtất cả các
│ │ *
└─────────────┴───────────┘

Đối với các thành phần nhật ký chỉ được đề cập trong NS_LOG

$ NS_LOG=" :..."

các tùy chọn tiền tố mặc định là LOG_PREFIX_ALL.

Mức độ nghiêm trọng Tiếp đầu ngữ
Mức độ nghiêm trọng của tin nhắn có thể được bao gồm trong các tùy chọn tiền tố_cấp or cấp.
Ví dụ, giá trị này của NS_LOG cho phép ghi nhật ký cho tất cả các thành phần nhật ký (`*') và tất cả
mức độ nghiêm trọng (= tất cả) và đặt trước thông báo mức độ nghiêm trọng (|prefix_level).

$ NS_LOG="*=all|prefix_level" ./waf --run Scratch-Simulator
Trình mô phỏng vết xước
[ERROR] thông báo lỗi
[WARN] thông báo cảnh báo
[DEBUG] thông báo gỡ lỗi
[THÔNG TIN] thông báo thông tin
Thông báo chức năng [FUNCT]
Thông báo logic [LOGIC]

Thời gian Tiếp đầu ngữ
Thời gian mô phỏng có thể được bao gồm trong các tùy chọn tiền tố_thời gian or thời gian. Điều này in
thời gian mô phỏng tính bằng giây.

Node Tiếp đầu ngữ
Id nút mô phỏng có thể được bao gồm trong các tùy chọn tiền tố_node or nút.

Chức năng Tiếp đầu ngữ
Tên của chức năng gọi có thể được bao gồm trong các tùy chọn tiền tố_func or chức năng.

NS_LOG Ký tự đại diện
Ký tự đại diện thành phần nhật ký `*' sẽ kích hoạt tất cả các thành phần. Để kích hoạt tất cả các thành phần tại một
sử dụng mức độ nghiêm trọng cụ thể *=.

Ký tự đại diện tùy chọn mức độ nghiêm trọng `*' là từ đồng nghĩa với tất cả các. Điều này phải xảy ra trước bất kỳ
`|' các tùy chọn tách ký tự. Để kích hoạt tất cả các lớp mức độ nghiêm trọng, hãy sử dụng =*,
or =*|.

Ký tự đại diện tùy chọn `*' hoặc mã thông báo tất cả các cho phép tất cả các tùy chọn tiền tố, nhưng phải xảy ra sau khi a
`|' tính cách. Để kích hoạt một lớp hoặc mức độ nghiêm trọng cụ thể và tất cả các tiền tố, hãy sử dụng
= |*.

Ký tự đại diện tùy chọn kết hợp ** cho phép tất cả các mức độ nghiêm trọng và tất cả các tiền tố; Ví dụ,
==.

Ký tự đại diện uber *** cho phép tất cả các mức độ nghiêm trọng và tất cả các tiền tố cho tất cả các thành phần nhật ký.
Tất cả đều tương đương:

$ NS_LOG="***" ... $ NS_LOG="*=all|*" ... $ NS_LOG="*=*|all" ...
$ NS_LOG="*=**" ... $ NS_LOG="*=level_all|*" ... $ NS_LOG="*=*|prefix_all" ...
$ NS_LOG="*=*|*" ...

Hãy lưu ý: ngay cả những điều tầm thường mô phỏng vết xước tạo ra hơn 46K dòng đầu ra với
NS_LOG="***"!

Làm thế nào đến thêm vào khai thác gỗ đến qua một vài thao tác đơn giản về
Việc thêm tính năng ghi nhật ký vào mã của bạn rất đơn giản:

1. Gọi NS_LOG_COMPONENT_DEFINE (...); vĩ mô bên trong không gian tên Ns3.
Tạo một mã định danh chuỗi duy nhất (thường dựa trên tên của tệp và/hoặc lớp
được xác định trong tệp) và đăng ký nó bằng lệnh gọi macro như sau:

không gian tên ns3 {

NS_LOG_COMPONENT_DEFINE ("Giao thức Ipv4L3");
...

Điều này đăng ký Giao thức Ipv4L3 như một thành phần nhật ký.

(Macro được viết cẩn thận để cho phép đưa vào bên trong hoặc bên ngoài
không gian tên Ns3và cách sử dụng sẽ khác nhau tùy theo cơ sở mã, nhưng mục đích ban đầu là
đăng ký cái này bên ngoài không gian tên Ns3 ở phạm vi toàn cầu của tệp.)

2. Thêm câu lệnh ghi nhật ký (lệnh macro) vào hàm và nội dung hàm của bạn.

Logging Macros
Các macro ghi nhật ký và mức độ nghiêm trọng liên quan là

┌───────────────┬─────────────────────── ─┐
│Lớp mức độ nghiêm trọng │ Vĩ mô │
├───────────────┼─────────────────────── ─┤
LOG_NONE │ (không cần thiết) │
├───────────────┼─────────────────────── ─┤
LOG_ERRORNS_LOG_ERROR (...);
├───────────────┼─────────────────────── ─┤
LOG_WARNNS_LOG_WARN (...);
├───────────────┼─────────────────────── ─┤
LOG_DEBUGNS_LOG_DEBUG (...);
├───────────────┼─────────────────────── ─┤
LOG_INFONS_LOG_INFO (...);
├───────────────┼─────────────────────── ─┤
LOG_FUNCTIONNS_LOG_FUNCTION (...);
├───────────────┼─────────────────────── ─┤
LOG_LOGICNS_LOG_LOGIC (...);
└───────────────┴─────────────────────── ─┘

Các macro hoạt động như bộ truyền phát đầu ra, vì vậy mọi thứ bạn có thể gửi tới std :: cout, đã tham gia
by << các nhà khai thác, được phép:

void MyClass::Check (giá trị int, char * item)
{
NS_LOG_FUNCTION (mục << arg << này);
nếu (arg > 10)
{
NS_LOG_ERROR ("gặp giá trị xấu" << giá trị <
" trong khi kiểm tra " << tên << "!");
}
...
}

Lưu ý rằng NS_LOG_FUNCTION tự động chèn một `,' (dấu phẩy) dấu phân cách giữa
mỗi lập luận của nó. Điều này giúp đơn giản hóa việc ghi nhật ký các đối số của hàm; chỉ cần nối
họ với << như trong ví dụ trên.

Vô điều kiện Logging
Như một sự tiện lợi, NS_LOG_UNCOND (...); macro sẽ luôn ghi lại các đối số của nó, ngay cả khi
thành phần nhật ký liên quan không được kích hoạt ở bất kỳ mức độ nghiêm trọng nào. Macro này không sử dụng bất kỳ
của các tùy chọn tiền tố. Lưu ý rằng tính năng ghi nhật ký chỉ được bật trong các bản dựng gỡ lỗi; vĩ mô này
sẽ không tạo ra đầu ra trong các bản dựng được tối ưu hóa.

Hướng dẫn
· Bắt đầu mọi phương thức lớp với NS_LOG_FUNCTION (điều này << tranh luận...); Điều này cho phép dễ dàng
theo dõi cuộc gọi chức năng.

· Ngoại trừ: không ghi nhật ký các toán tử hoặc hàm tạo sao chép rõ ràng, vì những điều này sẽ gây ra
đệ quy vô hạn và tràn ngăn xếp.

· Đối với các phương thức không có đối số sử dụng dạng tương tự: NS_LOG_FUNCTION (cái này);

· Đối với hàm tĩnh:

· Với việc sử dụng đối số NS_LOG_FUNCTION (...); như bình thường.

· Không sử dụng đối số NS_LOG_FUNCTION_NOARGS ();

· Sử dụng NS_LOG_ERROR đối với các điều kiện lỗi nghiêm trọng có thể làm mất hiệu lực mô phỏng
chấp hành.

· Sử dụng NS_LOG_WARN đối với các điều kiện bất thường có thể khắc phục được. Xin vui lòng cho một số gợi ý
về bản chất của vấn đề và cách khắc phục nó.

· NS_LOG_DEBUG thường được sử dụng trong một ad hoc cách để hiểu việc thực hiện một mô hình.

· Sử dụng NS_LOG_INFO để biết thêm thông tin về việc thực thi, chẳng hạn như kích thước của một
cấu trúc dữ liệu khi thêm/xóa khỏi nó.

· Sử dụng NS_LOG_LOGIC để theo dõi các nhánh logic quan trọng trong một hàm.

· Kiểm tra xem các thay đổi trong nhật ký của bạn có làm hỏng mã hay không. Chạy một số chương trình ví dụ với
tất cả các thành phần nhật ký được bật (ví dụ: NS_LOG="***").

Truy tìm
Hệ thống con theo dõi là một trong những cơ chế quan trọng nhất cần hiểu trong ns-3. Trong
hầu hết các trường hợp, ns-3 người dùng sẽ có một ý tưởng tuyệt vời cho một số mạng mới và được cải tiến
tính năng. Để xác minh rằng ý tưởng này có hiệu quả hay không, nhà nghiên cứu sẽ thực hiện những thay đổi đối với
hệ thống hiện có và sau đó chạy thử nghiệm để xem tính năng mới hoạt động như thế nào bằng cách thu thập
số liệu thống kê nắm bắt hành vi của đối tượng địa lý.

Nói cách khác, toàn bộ mục đích của việc chạy mô phỏng là tạo ra đầu ra cho
học. TRONG ns-3, hệ thống con cho phép nhà nghiên cứu thực hiện việc này là truy tìm
hệ thống con.

Truy tìm Động lực
Có nhiều cách để lấy thông tin ra khỏi một chương trình. Cách đơn giản nhất là
để in trực tiếp thông tin ra đầu ra tiêu chuẩn, như trong,

#bao gồm
...
intmain ()
{
...
std :: cout << "Giá trị của x là" << x << std :: endl;
...
}

Điều này có thể thực hiện được trong môi trường nhỏ, nhưng khi mô phỏng của bạn ngày càng nhiều
phức tạp, bạn sẽ phải tạo ra ngày càng nhiều bản in cũng như nhiệm vụ phân tích cú pháp và thực hiện
tính toán trên đầu ra bắt đầu ngày càng khó khăn hơn.

Một điều khác cần xem xét là mỗi khi cần một mẩu tin mới, lõi phần mềm
phải được chỉnh sửa và giới thiệu bản in khác. Không có cách tiêu chuẩn hóa để kiểm soát tất cả
của sản lượng này, do đó số lượng sản phẩm có xu hướng tăng lên không giới hạn. Cuối cùng,
băng thông cần thiết để xuất thông tin này bắt đầu giới hạn thời gian chạy
của mô phỏng. Các tập tin đầu ra phát triển đến kích thước khổng lồ và việc phân tích chúng trở thành một công việc khó khăn.
vấn đề.

ns-3 cung cấp một cơ chế đơn giản để ghi nhật ký và cung cấp một số quyền kiểm soát đầu ra thông qua
Khúc gỗ Linh kiện , nhưng mức độ kiểm soát không được tốt chút nào. Việc ghi nhật ký
module là một công cụ tương đối cùn.

Điều mong muốn là có một cơ sở cho phép người ta tiếp cận được hệ thống cốt lõi và chỉ
có được thông tin cần thiết mà không cần phải thay đổi và biên dịch lại hệ thống lõi. Thậm chí
tốt hơn sẽ là một hệ thống thông báo cho người dùng khi một mục quan tâm thay đổi hoặc một
sự kiện thú vị đã xảy ra.

ns-3 hệ thống theo dõi được thiết kế để hoạt động dọc theo những dòng đó và được tích hợp tốt với
các phần phụ Thuộc tính và Cấu hình cho phép thực hiện các tình huống sử dụng tương đối đơn giản.

Giới thiệu chung
Hệ thống con theo dõi phụ thuộc chủ yếu vào ns-3 Cơ chế gọi lại và thuộc tính. Bạn
nên đọc và hiểu các phần tương ứng của sách hướng dẫn trước khi cố gắng thực hiện
hiểu hệ thống theo dõi.

ns-3 hệ thống theo dõi được xây dựng dựa trên các khái niệm về các nguồn theo dõi độc lập và
truy tìm bồn rửa; cùng với một cơ chế thống nhất để kết nối nguồn với bồn.

Nguồn theo dõi là các thực thể có thể báo hiệu các sự kiện xảy ra trong mô phỏng và cung cấp
truy cập vào dữ liệu cơ bản thú vị. Ví dụ: một nguồn theo dõi có thể cho biết khi nào
gói được nhận bởi một thiết bị mạng và cung cấp quyền truy cập vào nội dung gói cho
dấu vết quan tâm chìm xuống. Nguồn theo dõi cũng có thể cho biết khi nào một trạng thái thú vị
thay đổi xảy ra trong một mô hình. Ví dụ, cửa sổ tắc nghẽn của một mô hình TCP là một
ứng cử viên cho nguồn vết.

Bản thân các nguồn theo dõi không hữu ích; chúng phải được kết nối với các đoạn mã khác
thực sự làm điều gì đó hữu ích với thông tin do nguồn cung cấp. Các
các thực thể tiêu thụ thông tin dấu vết được gọi là bể chứa dấu vết. Nguồn theo dõi là
người tạo ra sự kiện và người theo dõi là người tiêu dùng.

Sự phân chia rõ ràng này cho phép một số lượng lớn các nguồn dấu vết được phân tán xung quanh
hệ thống ở những nơi mà các tác giả mô hình tin rằng có thể hữu ích. Trừ khi người dùng kết nối một
dấu vết chìm vào một trong những nguồn này, không có gì là đầu ra. Sự sắp xếp này cho phép tương đối
người dùng đơn giản có thể gắn các loại bồn rửa mới vào các nguồn theo dõi hiện có mà không cần
yêu cầu chỉnh sửa và biên dịch lại lõi hoặc các mô hình của trình mô phỏng.

Có thể không có hoặc nhiều người tiêu thụ các sự kiện theo dõi được tạo ra bởi một nguồn xác định. Người ta có thể
hãy coi nguồn theo dõi như một loại liên kết thông tin điểm-đa điểm.

"Giao thức truyền tải" cho liên kết điểm-đa điểm mang tính khái niệm này là một ns-3 Gọi lại.

Hãy nhớ lại trong Phần gọi lại rằng cơ sở gọi lại là một cách để cho phép hai mô-đun trong
hệ thống giao tiếp thông qua các cuộc gọi chức năng đồng thời tách cuộc gọi
hoàn toàn hoạt động từ lớp được gọi. Đây là yêu cầu tương tự như đã nêu ở trên
cho hệ thống truy vết.

Về cơ bản, một nguồn dấu vết is một cuộc gọi lại mà nhiều chức năng có thể được đăng ký.
Khi một trace sink thể hiện sự quan tâm đến việc nhận các sự kiện theo dõi, nó sẽ thêm một lệnh gọi lại vào một
danh sách các cuộc gọi lại được giữ bởi nguồn theo dõi. Khi một sự kiện thú vị xảy ra, dấu vết
nguồn gọi nó nhà điều hành() cung cấp không hoặc nhiều tham số. Điều này cho biết nguồn
lần lượt xem qua danh sách các lệnh gọi lại và gọi từng lệnh gọi lại. Bằng cách này, (các) tham số
được truyền tới bộ chứa dấu vết, chúng chỉ là các chức năng.

Đơn giản nhất Ví dụ
Sẽ rất hữu ích khi xem một ví dụ nhanh để củng cố những gì chúng tôi đã nói.:

#include "ns3 / object.h"
#include "ns3 / uinteger.h"
#include "ns3/traced-value.h""
#include "ns3 / trace-source-accessor.h"

#bao gồm

sử dụng không gian tên ns3;

Điều đầu tiên cần làm là bao gồm các tập tin cần thiết. Như đã đề cập ở trên, hệ thống theo dõi
sử dụng nhiều hệ thống Đối tượng và Thuộc tính. Hai cái đầu tiên bao gồm mang lại
khai báo cho các hệ thống đó. Tập tin, truy tìm giá trị.h mang lại những gì cần thiết
các khai báo để truy tìm dữ liệu tuân theo ngữ nghĩa giá trị.

Nói chung, ngữ nghĩa giá trị chỉ có nghĩa là bạn có thể truyền đối tượng đi khắp nơi chứ không phải
Địa chỉ. Để sử dụng ngữ nghĩa giá trị, bạn phải có một đối tượng có
hàm tạo bản sao liên quan và toán tử gán có sẵn. Chúng tôi mở rộng các yêu cầu
để nói về tập hợp các toán tử được xác định trước cho các loại dữ liệu cũ (POD).
Toán tử=, toán tử++, toán tử--, toán tử+, toán tử==, v.v.

Tất cả điều này có nghĩa là bạn sẽ có thể theo dõi các thay đổi đối với một đối tượng được thực hiện bằng cách sử dụng
những toán tử đó.:

lớp MyObject: đối tượng công cộng
{
công khai:
TypeId tĩnh GetTypeId (khoảng trống)
{
static TypeId tid = TypeId ("MyObject")
.SetParent (Object :: GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MyInteger",
"Một giá trị số nguyên để theo dõi.",
MakeTraceSourceAccessor (&MyObject::m_myInt))
;
trả lại tid;
}

Đối tượng của tôi () {}
Giá trị truy tìm m_myInt;
};

Vì hệ thống theo dõi được tích hợp với Thuộc tính và Thuộc tính hoạt động với Đối tượng,
phải có một ns-3 Đối tượng để nguồn dấu vết tồn tại. Hai dòng quan trọng của
mã là .AddTraceSourceGiá trị truy tìm tờ khai.

.AddTraceSource cung cấp các "móc" được sử dụng để kết nối nguồn theo dõi với
thế giới bên ngoài. Các Giá trị truy tìm Tuyên bố cung cấp cơ sở hạ tầng làm quá tải
các toán tử được đề cập ở trên và thúc đẩy quá trình gọi lại.:

làm mất hiệu lực
IntTrace (Int oldValue, Int newValue)
{
std :: cout << "Traced" << oldValue << "to" << newValue << std :: endl;
}

Đây là định nghĩa của dấu vết chìm. Nó tương ứng trực tiếp với một chức năng gọi lại.
Hàm này sẽ được gọi bất cứ khi nào một trong các toán tử của Giá trị truy tìm is
Thực thi.:

int
main (int argc, char * argv [])
{
Ptr myObject = CreateObject ();

myObject-> TraceConnectWithoutContext ("MyInteger", MakeCallback (& ​​IntTrace));

myObject-> m_myInt = 1234;
}

Trong đoạn mã này, điều đầu tiên cần làm là tạo đối tượng trong đó
nguồn dấu vết sống.

Bước tiếp theo, TraceConnectWithoutContext, tạo thành kết nối giữa dấu vết
nguồn và bồn chứa dấu vết. Chú ý gọi lại chức năng mẫu. Nhớ lại từ
Phần gọi lại để tạo ra functor chuyên biệt chịu trách nhiệm cung cấp
quá tải nhà điều hành() được sử dụng để "kích hoạt" cuộc gọi lại. Các toán tử quá tải (++, --, v.v.)
sẽ sử dụng cái này nhà điều hành() để thực sự gọi lại cuộc gọi lại. Các TraceConnectWithoutContext,
lấy tham số chuỗi cung cấp tên của Thuộc tính được gán cho dấu vết
nguồn. Bây giờ chúng ta hãy bỏ qua một chút về bối cảnh vì nó chưa quan trọng.

Cuối cùng, dòng,:

myObject-> m_myInt = 1234;

nên được hiểu là một lời kêu gọi toán tử = trên biến thành viên m_myInt với
số nguyên 1234 được truyền dưới dạng tham số. Hóa ra toán tử này được định nghĩa (bởi
Giá trị truy tìm) để thực hiện lệnh gọi lại trả về void và nhận hai giá trị số nguyên làm
tham số -- một giá trị cũ và một giá trị mới cho số nguyên được đề cập. Đó chính xác là
chữ ký hàm cho hàm gọi lại mà chúng tôi đã cung cấp -- IntTrace.

Tóm lại, về bản chất, nguồn theo dõi là một biến chứa danh sách các lệnh gọi lại. MỘT
theo dõi chìm là một chức năng được sử dụng như mục tiêu của một cuộc gọi lại. Thuộc tính và loại đối tượng
hệ thống thông tin được sử dụng để cung cấp cách kết nối các nguồn theo dõi với các nguồn theo dõi. Các
hành động "đánh" một nguồn dấu vết đang thực thi một toán tử trên nguồn dấu vết kích hoạt
cuộc gọi lại. Điều này dẫn đến các cuộc gọi lại theo dõi chìm đăng ký sự quan tâm đến nguồn
được gọi với các tham số được cung cấp bởi nguồn.

Sử dụng các Config Hệ thống con đến Kết nối đến Dấu vết nguồn
TraceConnectWithoutContext cuộc gọi hiển thị ở trên trong ví dụ đơn giản thực sự rất
hiếm khi được sử dụng trong hệ thống. Điển hình hơn, Config hệ thống con được sử dụng để cho phép lựa chọn
nguồn dấu vết trong hệ thống bằng cách sử dụng cái được gọi là cấu hình con đường.

Ví dụ: người ta có thể tìm thấy thứ gì đó trông giống như sau trong hệ thống (được lấy
từ ví dụ/tcp-large-transfer.cc):

void CwndTracer (uint32_t oldval, uint32_t newval) {}

...

Cấu hình::ConnectWithoutContext (
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
MakeCallback (&CwndTracer));

Điều này trông rất quen thuộc. Nó giống như ví dụ trước, ngoại trừ việc
một hàm thành viên tĩnh của lớp Config đang được gọi thay vì một phương thức trên Đối tượng;
và thay vì một đặc tính tên, một đường dẫn đang được cung cấp.

Điều đầu tiên cần làm là đọc đường dẫn lùi. Đoạn cuối cùng của đường dẫn phải là
an đặc tính của một Đối tượng. Thực tế, nếu bạn có một con trỏ tới Đối tượng
"Cửa sổ tắc nghẽn" đặc tính tiện dụng (gọi nó là đối tượng), bạn có thể viết cái này giống như
ví dụ trước:

void CwndTracer (uint32_t oldval, uint32_t newval) {}

...

theObject->TraceConnectWithoutContext ("Tắc nghẽnWindow", MakeCallback (&CwndTracer));

Hóa ra là mã cho Cấu hình :: ConnectWithoutContext thực hiện chính xác điều đó. Cái này
hàm lấy một đường dẫn đại diện cho một chuỗi Đối tượng con trỏ và theo dõi chúng cho đến khi nó
đi đến cuối đường dẫn và hiểu đoạn cuối cùng là đặc tính vào cuối
sự vật. Chúng ta hãy xem những gì xảy ra.

Ký tự "/" đứng đầu trong đường dẫn đề cập đến cái gọi là không gian tên. Một trong những
không gian tên được xác định trước trong hệ thống cấu hình là "NodeList", là danh sách của tất cả
các nút trong mô phỏng. Các mục trong danh sách được tham chiếu bởi các chỉ số trong danh sách, vì vậy
"/NodeList/0" đề cập đến nút thứ XNUMX trong danh sách các nút được tạo bởi mô phỏng.
Nút này thực sự là một Ptr và một lớp con của một ns3 :: Đối tượng.

Như được mô tả trong phần Mô hình đối tượng, ns-3 hỗ trợ một mô hình tổng hợp đối tượng. Các
đoạn đường dẫn tiếp theo bắt đầu bằng ký tự "$" cho biết Nhận đối tượng cuộc gọi nên được
đã thực hiện tìm kiếm loại sau. Khi một nút được khởi tạo bởi một
InternetNgăn XếpTrợ Giúp một số giao diện được tổng hợp vào nút. Một trong số đó là
Giao thức TCP cấp 4. Kiểu thời gian chạy của đối tượng giao thức này là ns3::TcpL4Protocol''.
Thời Gian các ``GetObject được thực thi, nó trả về một con trỏ tới đối tượng thuộc loại này.

Giao thức TcpL4 lớp định nghĩa một Thuộc tính có tên là "SocketList" là danh sách các
ổ cắm. Mỗi ổ cắm thực sự là một ns3 :: Đối tượng với chính nó Thuộc tính. Các mục trong
danh sách các ổ cắm được tham chiếu theo chỉ mục giống như trong NodeList, vì vậy "SocketList/0"
đề cập đến ổ cắm thứ 0 trong danh sách các ổ cắm trên nút thứ 0 trong NodeList --
nút đầu tiên được xây dựng trong mô phỏng.

Ổ cắm này, loại của nó hóa ra là một ns3::TcpSocketImpl định nghĩa một thuộc tính
được gọi là "CongestionWindow" là một Giá trị truy tìm. Các
Cấu hình :: ConnectWithoutContext bây giờ thực hiện một,:

đối tượng->TraceConnectWithoutContext ("Tắc nghẽnWindow", MakeCallback (&CwndTracer));

sử dụng con trỏ đối tượng từ "SocketList/0" để tạo kết nối giữa dấu vết
nguồn được xác định trong ổ cắm cho lệnh gọi lại -- CwndTracer.

Bây giờ, bất cứ khi nào có sự thay đổi được thực hiện đối với Giá trị truy tìm đại diện cho sự tắc nghẽn
trong ổ cắm TCP, lệnh gọi lại đã đăng ký sẽ được thực thi và hàm
CwndTracer sẽ được gọi là in ra các giá trị cũ và mới của tắc nghẽn TCP
cửa sổ.

Sử dụng các Truy tìm API
Có ba cấp độ tương tác với hệ thống theo dõi:

· Người dùng mới bắt đầu có thể dễ dàng kiểm soát những đối tượng nào đang tham gia truy tìm;

· Người dùng trung gian có thể mở rộng hệ thống truy tìm để sửa đổi định dạng đầu ra được tạo
hoặc sử dụng các nguồn vi lượng hiện có theo những cách khác nhau mà không sửa đổi cốt lõi của
giả lập;

· Người dùng nâng cao có thể sửa đổi lõi mô phỏng để thêm các nguồn theo dõi và phần chìm mới.

Sử dụng Dấu vết Người giúp việc
ns-3 trình trợ giúp theo dõi cung cấp một môi trường phong phú để định cấu hình và lựa chọn các
theo dõi các sự kiện và ghi chúng vào tập tin. Trong các phần trước, chủ yếu là "Xây dựng
Cấu trúc liên kết", chúng tôi đã thấy một số phương pháp trợ giúp theo dõi được thiết kế để sử dụng
bên trong những người trợ giúp (thiết bị) khác.

Có lẽ bạn sẽ nhớ lại khi thấy một số biến thể sau:

pointToPoint.EnablePcapAll ("thứ hai");
pointToPoint.EnablePcap ("thứ hai", p2pNodes.Get (0) -> GetId (), 0);
csma.EnablePcap ("thứ ba", csmaDevices.Get (0), true);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Tuy nhiên, điều có thể không rõ ràng là có một mô hình nhất quán cho tất cả
các phương pháp liên quan đến dấu vết được tìm thấy trong hệ thống. Bây giờ chúng ta sẽ dành một chút thời gian và xem xét
tại "bức tranh lớn".

Hiện có hai trường hợp sử dụng chính của trình trợ giúp theo dõi trong ns-3: Trợ giúp thiết bị
và người trợ giúp giao thức. Người trợ giúp thiết bị xem xét vấn đề chỉ định dấu vết nào sẽ
được kích hoạt thông qua một nút, cặp thiết bị. Ví dụ: bạn có thể muốn chỉ định pcap đó
tính năng theo dõi phải được bật trên một thiết bị cụ thể trên một nút cụ thể. Điều này diễn ra từ
ns-3 mô hình khái niệm thiết bị và cả mô hình khái niệm của các thiết bị khác nhau
những người giúp đỡ. Theo cách tự nhiên từ điều này, các tập tin được tạo ra sẽ tuân theo một
- - quy ước đặt tên.

Người trợ giúp giao thức xem xét vấn đề chỉ định dấu vết nào nên được kích hoạt thông qua
một cặp giao thức và giao diện. Điều này theo sau từ ns-3 mô hình khái niệm ngăn xếp giao thức,
và cả các mô hình khái niệm về trình trợ giúp ngăn xếp internet. Đương nhiên, các tập tin dấu vết
nên làm theo một - - quy ước đặt tên.

Do đó, những người trợ giúp dấu vết tự nhiên rơi vào phân loại hai chiều. Có
sự tinh tế ngăn cản tất cả bốn lớp hành xử giống nhau, nhưng chúng tôi cố gắng
làm cho tất cả chúng hoạt động giống nhau nhất có thể; và bất cứ khi nào có thể, có các chất tương tự cho
tất cả các phương thức trong tất cả các lớp.

┌─────────────────┬──────┬───────
│ │ pcap │ ascii │
├─────────────────┼──────┼───────
│ Người trợ giúp thiết bị │ │ │
├─────────────────┼──────┼───────
│Trợ giúp giao thức │ │ │
└─────────────────┴──────┴───────

Chúng tôi sử dụng một cách tiếp cận được gọi là hỗn hợp để thêm chức năng theo dõi vào các lớp trợ giúp của chúng tôi. MỘT
hỗn hợp là một lớp cung cấp chức năng được kế thừa bởi một lớp con.
Kế thừa từ mixin không được coi là một hình thức chuyên môn hóa nhưng thực sự là một cách để
chức năng thu thập.

Chúng ta hãy xem xét nhanh tất cả bốn trường hợp này và các trường hợp tương ứng mixin.

pcap Truy tìm Dụng cụ Người giúp việc
Mục tiêu của những người trợ giúp này là giúp dễ dàng thêm tiện ích theo dõi pcap nhất quán vào
ns-3 thiết bị. Chúng tôi muốn tất cả các kiểu truy tìm pcap khác nhau hoạt động giống nhau trên
tất cả các thiết bị, vì vậy các phương pháp của các trình trợ giúp này được kế thừa bởi các trình trợ giúp của thiết bị. Hãy xem
at src / network / helper / trace-helper.h nếu bạn muốn theo dõi cuộc thảo luận trong khi xem xét
mã thực.

Lớp PcapTrợ giúp cho thiết bị là một hỗn hợp cung cấp chức năng cấp cao để sử dụng
truy tìm pcap trong một ns-3 thiết bị. Mọi thiết bị phải triển khai một phương thức ảo duy nhất
kế thừa từ lớp này.:

khoảng trống ảo EnablePcapInternal (tiền tố chuỗi std ::, Ptr nd, bool lăng nhăng) = 0;

Chữ ký của phương pháp này phản ánh quan điểm tập trung vào thiết bị của tình huống tại thời điểm này
mức độ. Tất cả các phương thức công khai được kế thừa từ lớp PcapUserHelperForDevice giảm xuống
gọi phương thức triển khai phụ thuộc vào thiết bị duy nhất này. Ví dụ, mức thấp nhất
phương pháp pcap,:

void EnablePcap (tiền tố std :: string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);

sẽ gọi việc triển khai thiết bị của Kích hoạtPcapInternal trực tiếp. Tất cả các pcap công cộng khác
các phương pháp theo dõi được xây dựng dựa trên triển khai này để cung cấp thêm cấp độ người dùng
chức năng. Điều này có nghĩa là gì đối với người dùng là tất cả những người trợ giúp thiết bị trong hệ thống sẽ
có sẵn tất cả các phương pháp theo dõi pcap; và tất cả các phương pháp này sẽ hoạt động giống nhau
giữa các thiết bị nếu thiết bị triển khai Kích hoạtPcapInternal đúng.

pcap Truy tìm Dụng cụ Người giúp đỡ Phương pháp
void EnablePcap (std::tiền tố chuỗi, Ptr thứ,
bool lăng nhăng = false, bool rõ ràngFilename = false);
void EnablePcap (tiền tố std::string, std::string ndName,
bool lăng nhăng = false, bool rõ ràngFilename = false);
void EnablePcap (std::tiền tố chuỗi, NetDeviceContainer d,
bool lăng nhăng = sai);
void EnablePcap (std::tiền tố chuỗi, NodeContainer n,
bool lăng nhăng = sai);
void EnablePcap (std::tiền tố chuỗi, uint32_t nodeid, uint32_t deviceid,
bool lăng nhăng = sai);
void EnablePcapAll (tiền tố std :: string, bool promiscuous = false);

Trong mỗi phương thức được hiển thị ở trên, có một tham số mặc định được gọi là promiscuous việc này
mặc định là sai. Tham số này chỉ ra rằng dấu vết không nên được thu thập trong
chế độ lăng nhăng. Nếu bạn muốn dấu vết của mình bao gồm tất cả lưu lượng mà thiết bị nhìn thấy
(và nếu thiết bị hỗ trợ chế độ quảng cáo) chỉ cần thêm một tham số true vào bất kỳ
cuộc gọi ở trên. Ví dụ,:

Ptr nd;
...
helper.EnablePcap ("tiền tố", nd, true);

sẽ cho phép chụp chế độ lăng nhăng trên thiết bị mạng theo quy định của nd.

Hai phương thức đầu tiên cũng bao gồm một tham số mặc định được gọi là tên tệp rõ ràng răng se
được thảo luận dưới đây.

Bạn được khuyến khích đọc Doxygen cho lớp học PcapTrợ giúp cho thiết bị để tìm chi tiết
của các phương pháp này; nhưng tóm lại...

Bạn có thể kích hoạt tính năng theo dõi pcap trên một cặp nút/thiết bị mạng cụ thể bằng cách cung cấp
Ptr đến một Kích hoạtPcap phương pháp. Các Ptr là ẩn vì thiết bị mạng
phải thuộc về chính xác một Node. Ví dụ,:

Ptr nd;
...
helper.EnablePcap ("tiền tố", nd);

Bạn có thể kích hoạt tính năng theo dõi pcap trên một cặp nút/thiết bị mạng cụ thể bằng cách cung cấp
std :: string đại diện cho một chuỗi dịch vụ tên đối tượng thành một Kích hoạtPcap phương pháp. Các
Ptr được tra cứu từ chuỗi tên. Một lần nữa, là ngầm định vì
thiết bị mạng được đặt tên phải thuộc về chính xác một Node. Ví dụ,:

Names :: Add ("server" ...);
Names :: Add ("server / eth0" ...);
...
helper.EnablePcap ("tiền tố", "máy chủ / Ath0");

Bạn có thể kích hoạt tính năng theo dõi pcap trên một tập hợp các cặp nút/thiết bị mạng bằng cách cung cấp một
NetThiết BịContainer. Cho mỗi thiết bị mạng trong hộp chứa loại được kiểm tra. Cho mỗi
thiết bị thuộc loại thích hợp (cùng loại được quản lý bởi trình trợ giúp thiết bị), theo dõi là
đã được kích hoạt. Một lần nữa, là ẩn vì thiết bị mạng được tìm thấy phải thuộc về chính xác
một Node. Ví dụ,:

NetDeviceContainer d = ...;
...
helper.EnablePcap ("tiền tố", d);

Bạn có thể kích hoạt tính năng theo dõi pcap trên một tập hợp các cặp nút/thiết bị mạng bằng cách cung cấp một
NútContainer. Cho mỗi Node trong NútContainer nó đính kèm thiết bị mạng được lặp lại.
Cho mỗi thiết bị mạng được gắn vào mỗi nút trong vùng chứa, loại thiết bị đó là
đã kiểm tra. Đối với từng thiết bị thuộc loại thích hợp (cùng loại được thiết bị quản lý
helper), tính năng theo dõi được bật.:

nútContainer n;
...
helper.EnablePcap ("tiền tố", n);

Bạn có thể kích hoạt tính năng theo dõi pcap trên cơ sở ID nút và ID thiết bị cũng như với thông tin rõ ràng
ptr. Mỗi Node trong hệ thống có ID nút số nguyên và mỗi thiết bị được kết nối với một nút
có ID thiết bị nguyên.:

helper.EnablePcap ("tiền tố", 21, 1);

Cuối cùng, bạn có thể bật tính năng theo dõi pcap cho tất cả các thiết bị trong hệ thống, cùng loại với
được quản lý bởi người trợ giúp thiết bị.:

helper.EnablePcapAll ("tiền tố");

pcap Truy tìm Dụng cụ Người giúp đỡ Tên tập tin Lựa chọn
Ngụ ý trong các mô tả phương pháp ở trên là việc xây dựng một tên tệp hoàn chỉnh bằng cách
phương pháp thực hiện. Theo quy ước, dấu vết của pcap trong ns-3 hệ thống có dạng
- id> - id> .pcap

Như đã đề cập trước đó, mọi nút trong hệ thống sẽ có id nút do hệ thống gán; Và
mọi thiết bị sẽ có một chỉ mục giao diện (còn được gọi là id thiết bị) liên quan đến nút của nó.
Theo mặc định, tệp theo dõi pcap được tạo do bật tính năng theo dõi ở lần đầu tiên.
thiết bị của nút 21 sử dụng tiền tố "tiền tố" sẽ là tiền tố-21-1.pcap.

Bạn luôn có thể sử dụng ns-3 dịch vụ tên đối tượng để làm cho điều này rõ ràng hơn. Ví dụ, nếu
bạn sử dụng dịch vụ tên đối tượng để gán tên "máy chủ" cho nút 21, kết quả là pcap
tên tệp theo dõi sẽ tự động trở thành, tiền tố-máy chủ-1.pcap và nếu bạn cũng chỉ định
đặt tên "eth0" cho thiết bị, tên tệp pcap của bạn sẽ tự động chọn tên này và
gọi là tiền tố-máy chủ-eth0.pcap.

Cuối cùng, hai trong số các phương pháp được hiển thị ở trên,:

void EnablePcap (tiền tố std :: string, Ptr nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std :: string prefix, std :: string ndName, bool promiscuous = false, bool explicitFilename = false);

có một tham số mặc định được gọi là tên tệp rõ ràng. Khi được đặt thành true, thông số này
vô hiệu hóa cơ chế hoàn thành tên tệp tự động và cho phép bạn tạo
tên tập tin. Tùy chọn này chỉ khả dụng trong các phương pháp cho phép theo dõi pcap trên
thiết bị duy nhất.

Ví dụ: để sắp xếp một trình trợ giúp thiết bị tạo một pcap bừa bãi duy nhất
chụp tập tin của một tên cụ thể (my-pcap-file.pcap) trên một thiết bị nhất định, người ta có thể:

Ptr nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);

Lần đầu tiên đúng tham số cho phép theo dõi chế độ lăng nhăng và thông số thứ hai cho người trợ giúp
để giải thích tiếp đầu ngữ tham số như một tên tệp hoàn chỉnh.

Thăng thiên Truy tìm Dụng cụ Người giúp việc
Hành vi của người trợ giúp theo dõi ascii hỗn hợp về cơ bản là giống với phiên bản pcap.
Hãy xem src / network / helper / trace-helper.h nếu bạn muốn theo dõi cuộc thảo luận
trong khi nhìn vào mã thực.

Lớp AsciiTraceHelperForDevice thêm chức năng cấp cao để sử dụng ascii
truy tìm lớp trợ giúp thiết bị. Như trong trường hợp pcap, mọi thiết bị đều phải triển khai một
phương thức ảo duy nhất được kế thừa từ dấu vết ascii hỗn hợp.:

khoảng trống ảo EnableAsciiInternal (Ptr luồng, tiền tố chuỗi std::, Ptr nd) = 0;

Chữ ký của phương pháp này phản ánh quan điểm tập trung vào thiết bị của tình huống tại thời điểm này
mức độ; và thực tế là người trợ giúp có thể đang ghi vào một luồng đầu ra được chia sẻ. Tất cả
các phương thức liên quan đến dấu vết ascii công khai được kế thừa từ lớp AsciiTraceHelperForDevice
giảm xuống việc gọi phương thức triển khai phụ thuộc vào thiết bị duy nhất này. Ví dụ,
phương pháp theo dõi ascii cấp thấp nhất,:

void EnableAscii (std::tiền tố chuỗi, Ptr thứ);
void EnableAscii (Ptr luồng, Ptr nd);

sẽ gọi việc triển khai thiết bị của Kích hoạt AsciiInternal trực tiếp, cung cấp một
tiền tố hoặc luồng hợp lệ. Tất cả các phương pháp truy tìm ascii công khai khác sẽ được xây dựng dựa trên những phương pháp này
chức năng cấp thấp để cung cấp chức năng cấp độ người dùng bổ sung. Điều này có ý nghĩa gì với
người dùng là tất cả người trợ giúp thiết bị trong hệ thống sẽ có tất cả các phương pháp theo dõi ascii
có sẵn; và tất cả các phương pháp này sẽ hoạt động theo cùng một cách trên các thiết bị nếu thiết bị
thực hiện EnableAsciiInternal đúng.

Thăng thiên Truy tìm Dụng cụ Người giúp đỡ Phương pháp
void EnableAscii (std::tiền tố chuỗi, Ptr thứ);
void EnableAscii (Ptr luồng, Ptr nd);

void EnableAscii (tiền tố std::string, std::string ndName);
void EnableAscii (Ptr stream, std :: string ndName);

void EnableAscii (tiền tố std :: string, NetDeviceContainer d);
void EnableAscii (Ptr luồng, NetDeviceContainer d);

void EnableAscii (tiền tố std :: string, NodeContainer n);
void EnableAscii (Ptr luồng, NodeContainer n);

void EnableAscii (std::tiền tố chuỗi, uint32_t nodeid, uint32_t deviceid);
void EnableAscii (Ptr luồng, uint32_t nodeid, uint32_t deviceid);

void EnableAsciiAll (tiền tố std :: string);
void EnableAsciiAll (Ptr dòng);

Bạn được khuyến khích đọc Doxygen cho lớp học TraceHelperForDevice để tìm
chi tiết của các phương pháp này; nhưng tóm lại ...

Có số phương pháp truy tìm ascii nhiều gấp đôi so với pcap
truy tìm. Điều này là do, ngoài mô hình kiểu pcap nơi có dấu vết từ mỗi
cặp nút / thiết bị duy nhất được ghi vào một tệp duy nhất, chúng tôi hỗ trợ một mô hình trong đó theo dõi
thông tin cho nhiều cặp nút / thiết bị được ghi vào một tệp chung. Điều này có nghĩa là
- - cơ chế tạo tên tệp được thay thế bằng cơ chế
tham khảo một tập tin chung; và số lượng các phương thức API được tăng gấp đôi để cho phép tất cả
các tổ hợp.

Giống như trong việc theo dõi pcap, bạn có thể kích hoạt tính năng theo dõi ascii trên một cặp nút/thiết bị mạng cụ thể
bằng cách cung cấp một Ptr đến một BậtAscii phương pháp. Các Ptr là ngầm kể từ khi
thiết bị mạng phải thuộc về chính xác một Node. Ví dụ,:

Ptr nd;
...
helper.EnableAscii ("tiền tố", nd);

Trong trường hợp này, không có ngữ cảnh theo dõi nào được ghi vào tệp dấu vết ascii vì chúng sẽ
dư thừa. Hệ thống sẽ chọn tên tệp sẽ được tạo bằng cách sử dụng các quy tắc tương tự như
được mô tả trong phần pcap, ngoại trừ việc tệp sẽ có hậu tố ".tr" thay vì
".pcap".

Nếu bạn muốn bật tính năng theo dõi ascii trên nhiều thiết bị mạng và gửi tất cả dấu vết
vào một tệp duy nhất, bạn cũng có thể làm điều đó bằng cách sử dụng một đối tượng để tham chiếu đến một tệp duy nhất:

Ptr nd1;
Ptr nd2;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
người trợ giúp.EnableAscii (luồng, nd1);
người trợ giúp.EnableAscii (luồng, nd2);

Trong trường hợp này, ngữ cảnh theo dõi được ghi vào tệp theo dõi ascii vì chúng được yêu cầu
để phân biệt dấu vết từ hai thiết bị. Lưu ý rằng vì người dùng hoàn toàn
chỉ định tên tệp, chuỗi phải bao gồm ".tr" để thống nhất.

Bạn có thể kích hoạt tính năng theo dõi ascii trên một cặp nút/thiết bị mạng cụ thể bằng cách cung cấp
std :: string đại diện cho một chuỗi dịch vụ tên đối tượng thành một Kích hoạtPcap phương pháp. Các
Ptr được tra cứu từ chuỗi tên. Một lần nữa, là ngầm định vì
thiết bị mạng được đặt tên phải thuộc về chính xác một Node. Ví dụ,:

Names :: Add ("client" ...);
Names :: Add ("client / eth0" ...);
Names :: Add ("server" ...);
Names :: Add ("server / eth0" ...);
...
helper.EnableAscii ("tiền tố", "khách hàng / eth0");
helper.EnableAscii ("tiền tố", "máy chủ / eth0");

Điều này sẽ dẫn đến hai tập tin có tên tiền tố-client-eth0.trtiền tố-máy chủ-eth0.tr với
dấu vết cho từng thiết bị trong tệp dấu vết tương ứng. Vì tất cả EnableAscii
các hàm bị quá tải để lấy trình bao bọc luồng, bạn cũng có thể sử dụng biểu mẫu đó:

Names :: Add ("client" ...);
Names :: Add ("client / eth0" ...);
Names :: Add ("server" ...);
Names :: Add ("server / eth0" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (stream, "client / eth0");
helper.EnableAscii (luồng, "máy chủ / eth0");

Điều này sẽ dẫn đến một tệp theo dõi duy nhất được gọi là dấu vết-file-name.tr chứa tất cả
các sự kiện theo dõi cho cả hai thiết bị. Các sự kiện sẽ được phân biệt theo ngữ cảnh theo dõi
dây.

Bạn có thể kích hoạt tính năng theo dõi ascii trên một tập hợp các cặp nút/thiết bị mạng bằng cách cung cấp
NetThiết BịContainer. Cho mỗi thiết bị mạng trong hộp chứa loại được kiểm tra. Cho mỗi
thiết bị thuộc loại thích hợp (cùng loại được quản lý bởi trình trợ giúp thiết bị), theo dõi là
đã được kích hoạt. Một lần nữa, là ẩn vì thiết bị mạng được tìm thấy phải thuộc về chính xác
một Node. Ví dụ,:

NetDeviceContainer d = ...;
...
helper.EnableAscii ("tiền tố", d);

Điều này sẽ dẫn đến một số tệp dấu vết ascii được tạo, mỗi tệp theo sau
các - - quy ước .tr. Kết hợp tất cả các dấu vết thành một
một tệp được thực hiện tương tự như các ví dụ trên:

NetDeviceContainer d = ...;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
người trợ giúp.EnableAscii (luồng, d);

Bạn có thể kích hoạt tính năng theo dõi ascii trên một tập hợp các cặp nút/thiết bị mạng bằng cách cung cấp
NútContainer. Cho mỗi Node trong NútContainer nó đính kèm thiết bị mạng được lặp lại.
Cho mỗi thiết bị mạng được gắn vào mỗi nút trong vùng chứa, loại thiết bị đó là
đã kiểm tra. Đối với từng thiết bị thuộc loại thích hợp (cùng loại được thiết bị quản lý
helper), tính năng theo dõi được bật.:

nútContainer n;
...
helper.EnableAscii ("tiền tố", n);

Điều này sẽ dẫn đến một số tệp dấu vết ascii được tạo, mỗi tệp theo sau
các - - quy ước .tr. Kết hợp tất cả các dấu vết thành một
một tệp được thực hiện tương tự như các ví dụ trên:

Bạn có thể kích hoạt tính năng theo dõi pcap trên cơ sở ID nút và ID thiết bị cũng như với thông tin rõ ràng
ptr. Mỗi Node trong hệ thống có ID nút số nguyên và mỗi thiết bị được kết nối với một nút
có ID thiết bị nguyên.:

helper.EnableAscii ("tiền tố", 21, 1);

Tất nhiên, các dấu vết có thể được kết hợp thành một tệp duy nhất như hình trên.

Cuối cùng, bạn có thể bật tính năng theo dõi pcap cho tất cả các thiết bị trong hệ thống, cùng loại với
được quản lý bởi người trợ giúp thiết bị.:

helper.EnableAsciiAll ("tiền tố");

Điều này sẽ dẫn đến một số tệp dấu vết ascii được tạo, một tệp cho mọi thiết bị trong
hệ thống thuộc loại được quản lý bởi người trợ giúp. Tất cả các tập tin này sẽ tuân theo
- - quy ước .tr. Kết hợp tất cả các dấu vết thành một
tệp được thực hiện tương tự như các ví dụ trên.

Thăng thiên Truy tìm Dụng cụ Người giúp đỡ Tên tập tin Lựa chọn
Ngụ ý trong các mô tả phương pháp kiểu tiền tố ở trên là việc xây dựng hoàn chỉnh
tên tập tin theo phương pháp thực hiện. Theo quy ước, dấu vết ascii trong ns-3 hệ thống là
của hình thức - id> - id> .tr.

Như đã đề cập trước đó, mọi nút trong hệ thống sẽ có id nút do hệ thống gán; Và
mọi thiết bị sẽ có một chỉ mục giao diện (còn được gọi là id thiết bị) liên quan đến nút của nó.
Theo mặc định, tệp theo dõi ascii được tạo do bật tính năng theo dõi ở lần đầu tiên.
thiết bị của nút 21, sử dụng tiền tố "tiền tố", sẽ là tiền tố-21-1.tr.

Bạn luôn có thể sử dụng ns-3 dịch vụ tên đối tượng để làm cho điều này rõ ràng hơn. Ví dụ, nếu
bạn sử dụng dịch vụ tên đối tượng để gán tên "máy chủ" cho nút 21, kết quả
tên tệp dấu vết ascii sẽ tự động trở thành, tiền tố-máy chủ-1.tr và nếu bạn cũng chỉ định
tên "eth0" cho thiết bị, tên tệp theo dõi ascii của bạn sẽ tự động nhận tên này
và được gọi là tiền tố-máy chủ-eth0.tr.

pcap Truy tìm Nghị định thư Người giúp việc
Mục tiêu của những mixin là giúp dễ dàng thêm phương tiện theo dõi pcap nhất quán vào
giao thức. Chúng tôi muốn tất cả các loại truy tìm pcap khác nhau hoạt động giống nhau trên tất cả
các giao thức, vì vậy các phương thức của các trình trợ giúp này được kế thừa bởi các trình trợ giúp ngăn xếp. Hãy xem
src / network / helper / trace-helper.h nếu bạn muốn theo dõi cuộc thảo luận trong khi xem xét
mã thực.

Trong phần này, chúng tôi sẽ minh họa các phương pháp được áp dụng cho giao thức IPv4. Đến
chỉ định dấu vết trong các giao thức tương tự, chỉ cần thay thế kiểu thích hợp. Ví dụ,
sử dụng một Ptr thay vì Ptr và gọi BậtPcapIpv6 thay vì BậtPcapIpv4.

Lớp PcapHelperForIpv4 cung cấp chức năng cấp cao để sử dụng tính năng theo dõi pcap
trong IPv4 giao thức. Mỗi trình trợ giúp giao thức kích hoạt các phương pháp này phải triển khai một
phương thức ảo kế thừa từ lớp này. Sẽ có một triển khai riêng cho
IPv6, chẳng hạn, nhưng sự khác biệt duy nhất sẽ nằm ở tên phương thức và chữ ký.
Các tên phương thức khác nhau được yêu cầu để phân biệt lớp IPv4 từ IPv6 đó là cả hai
bắt nguồn từ lớp Đối tượngvà các phương thức có chung chữ ký.:

khoảng trống ảo EnablePcapIpv4Internal (tiền tố chuỗi std::, Ptr giao diện ipv4, uint4_t) = 32;

Chữ ký của phương pháp này phản ánh giao thức và chế độ xem tập trung vào giao diện của
tình hình ở cấp độ này. Tất cả các phương thức công khai được kế thừa từ lớp PcapHelperForIpv4
giảm để gọi phương thức triển khai phụ thuộc vào thiết bị duy nhất này. Ví dụ,
phương pháp pcap cấp thấp nhất,:

void EnablePcapIpv4 (tiền tố std::string, Ptr giao diện ipv4, uint4_t);

sẽ gọi việc triển khai thiết bị của Kích hoạtPcapIpv4Internal trực tiếp. Tất cả công chúng khác
Các phương pháp theo dõi pcap được xây dựng dựa trên việc triển khai này để cung cấp thêm cấp độ người dùng
chức năng. Điều này có ý nghĩa gì với người dùng là tất cả những người trợ giúp giao thức trong hệ thống sẽ
có sẵn tất cả các phương pháp theo dõi pcap; và tất cả các phương pháp này sẽ hoạt động giống nhau
xuyên suốt các giao thức nếu người trợ giúp thực hiện Kích hoạtPcapIpv4Internal đúng.

pcap Truy tìm Nghị định thư Người giúp đỡ Phương pháp
Các phương pháp này được thiết kế để tương ứng một-một với Node- Và
thiết bị mạng- phiên bản trung tâm của các phiên bản thiết bị. Thay vì Nodethiết bị mạng đôi
các ràng buộc, chúng tôi sử dụng các ràng buộc về giao thức và giao diện.

Lưu ý rằng giống như trong phiên bản thiết bị, có sáu phương pháp:

void EnablePcapIpv4 (tiền tố std::string, Ptr giao diện ipv4, uint4_t);
void EnablePcapIpv4 (tiền tố std::string, std::string ipv4Name, giao diện uint32_t);
void EnablePcapIpv4 (tiền tố std :: string, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (tiền tố std :: string, NodeContainer n);
void EnablePcapIpv4 (tiền tố std::string, uint32_t nodeid, giao diện uint32_t);
void EnablePcapIpv4All (tiền tố std :: string);

Bạn được khuyến khích đọc Doxygen cho lớp học PcapHelperForIpv4 để tìm chi tiết
của các phương pháp này; nhưng tóm lại...

Bạn có thể kích hoạt tính năng theo dõi pcap trên một cặp giao thức/giao diện cụ thể bằng cách cung cấp một
Ptrgiao diện đến một Kích hoạtPcap phương pháp. Ví dụ,:

Ptr ipv4 = node-> GetObject ();
...
helper.EnablePcapIpv4 ("tiền tố", ipv4, 0);

Bạn có thể kích hoạt tính năng theo dõi pcap trên một cặp nút/thiết bị mạng cụ thể bằng cách cung cấp
std :: string đại diện cho một chuỗi dịch vụ tên đối tượng thành một Kích hoạtPcap phương pháp. Các
Ptr được tra cứu từ chuỗi tên. Ví dụ,:

Tên :: Thêm ("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("tiền tố", "serverIpv4", 1);

Bạn có thể kích hoạt tính năng theo dõi pcap trên một tập hợp các cặp giao thức/giao diện bằng cách cung cấp một
Bộ chứa giao diện Ipv4. Cho mỗi IPv4 / cặp giao diện trong vùng chứa loại giao thức
được kiểm tra. Đối với mỗi giao thức thuộc loại thích hợp (cùng loại được quản lý bởi
trợ giúp thiết bị), tính năng theo dõi được bật cho giao diện tương ứng. Ví dụ,:

Các nút NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (các nút);
...
Ipv4AddressTrợ giúp ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer giao diện = ipv4.Assign (thiết bị);
...
helper.EnablePcapIpv4 ("tiền tố", giao diện);

Bạn có thể kích hoạt tính năng theo dõi pcap trên một tập hợp các cặp giao thức/giao diện bằng cách cung cấp một
NútContainer. Cho mỗi Node trong NútContainer giao thức thích hợp được tìm thấy. Vì
mỗi giao thức, các giao diện của nó được liệt kê và việc theo dõi được kích hoạt trên kết quả
cặp. Ví dụ,:

nútContainer n;
...
helper.EnablePcapIpv4 ("tiền tố", n);

Bạn cũng có thể kích hoạt tính năng theo dõi pcap trên cơ sở ID nút và giao diện. Trong trường hợp này,
node-id được dịch sang một Ptr và giao thức thích hợp được tra cứu trong
nút. Giao thức và giao diện kết quả được sử dụng để chỉ định dấu vết kết quả
nguồn.:

helper.EnablePcapIpv4 ("tiền tố", 21, 1);

Cuối cùng, bạn có thể kích hoạt tính năng theo dõi pcap cho tất cả các giao diện trong hệ thống, với các
giao thức có cùng loại với giao thức được quản lý bởi trình trợ giúp thiết bị.:

helper.EnablePcapIpv4All ("tiền tố");

pcap Truy tìm Nghị định thư Người giúp đỡ Tên tập tin Lựa chọn
Ngụ ý trong tất cả các mô tả phương pháp ở trên là việc xây dựng hoàn chỉnh
tên tập tin theo phương pháp thực hiện. Theo quy ước, dấu vết pcap được lấy cho các thiết bị trong
các ns-3 hệ thống có dạng - id> - id> .pcap. Trong trường hợp
theo dõi giao thức, có sự tương ứng XNUMX-XNUMX giữa các giao thức và Nodes. Đây là
bởi vì giao thức Đối tượng được tổng hợp thành Node Đối tượng. Vì không có giao thức toàn cầu
id trong hệ thống, chúng ta sử dụng id nút tương ứng trong việc đặt tên file. Vì thế có một
khả năng xung đột tên tệp trong tên tệp theo dõi được chọn tự động. Vì điều này
lý do, quy ước tên tệp bị thay đổi đối với dấu vết giao thức.

Như đã đề cập trước đó, mọi nút trong hệ thống sẽ có id nút do hệ thống gán.
Vì có sự tương ứng một-một giữa các phiên bản giao thức và phiên bản nút
chúng tôi sử dụng id nút. Mỗi giao diện có một id giao diện tương ứng với giao thức của nó. Chúng tôi sử dụng
quy ước " -n -tôi .pcap "để đặt tên tệp theo dõi trong
người trợ giúp giao thức.

Do đó, theo mặc định, tệp theo dõi pcap được tạo do bật tính năng theo dõi
giao diện 1 của giao thức Ipv4 của nút 21 sử dụng tiền tố "tiền tố" sẽ là
"tiền tố-n21-i1.pcap".

Bạn luôn có thể sử dụng ns-3 dịch vụ tên đối tượng để làm cho điều này rõ ràng hơn. Ví dụ, nếu
bạn sử dụng dịch vụ tên đối tượng để gán tên "serverIpv4" cho Ptr trên nút
21, tên tệp theo dõi pcap kết quả sẽ tự động trở thành,
"prefix-nserverIpv4-i1.pcap".

Thăng thiên Truy tìm Nghị định thư Người giúp việc
Hoạt động của trình trợ giúp theo dõi ascii về cơ bản tương tự như trường hợp pcap. Lấy một
xem xét src / network / helper / trace-helper.h nếu bạn muốn theo dõi cuộc thảo luận trong khi
nhìn vào mã thực.

Trong phần này, chúng tôi sẽ minh họa các phương pháp được áp dụng cho giao thức IPv4. Đến
chỉ định dấu vết trong các giao thức tương tự, chỉ cần thay thế kiểu thích hợp. Ví dụ,
sử dụng một Ptr thay vì Ptr và gọi BậtAsciiIpv6 thay vì
BậtAsciiIpv4.

Lớp AsciiTraceHelperForIpv4 thêm chức năng cấp cao để sử dụng ascii
truy tìm người trợ giúp giao thức. Mỗi giao thức cho phép các phương pháp này phải triển khai
phương thức ảo duy nhất được kế thừa từ lớp này.:

khoảng trống ảo EnableAsciiIpv4Internal (Ptr luồng, tiền tố chuỗi std ::,
Ptr giao diện ipv4, uint4_t) = 32;

Chữ ký của phương pháp này phản ánh quan điểm tập trung vào giao thức và giao diện của
tình hình ở cấp độ này; và thực tế là người trợ giúp có thể viết thư cho một
luồng đầu ra. Tất cả các phương thức công khai được kế thừa từ lớp
PcapAndAsciiTraceHelperForIpv4 giảm gọi này phụ thuộc vào thiết bị duy nhất
phương pháp thực hiện. Ví dụ: các phương pháp theo dõi ascii cấp thấp nhất,:

void EnableAsciiIpv4 (tiền tố chuỗi std::, Ptr giao diện ipv4, uint4_t);
void EnableAsciiIpv4 (Ptr luồng, Ptr giao diện ipv4, uint4_t);

sẽ gọi việc triển khai thiết bị của Kích hoạtAsciiIpv4Internal trực tiếp, cung cấp một trong hai
tiền tố hoặc luồng. Tất cả các phương pháp truy tìm ascii công khai khác sẽ được xây dựng dựa trên những phương pháp này
chức năng cấp thấp để cung cấp chức năng cấp độ người dùng bổ sung. Điều này có ý nghĩa gì với
người dùng là tất cả người trợ giúp thiết bị trong hệ thống sẽ có tất cả các phương pháp theo dõi ascii
có sẵn; và tất cả các phương pháp này sẽ hoạt động theo cùng một cách trên các giao thức nếu
giao thức thực hiện EnableAsciiIpv4Internal đúng.

Thăng thiên Truy tìm Dụng cụ Người giúp đỡ Phương pháp
void EnableAsciiIpv4 (tiền tố chuỗi std::, Ptr giao diện ipv4, uint4_t);
void EnableAsciiIpv4 (Ptr luồng, Ptr giao diện ipv4, uint4_t);

void EnableAsciiIpv4 (tiền tố std::string, std::string ipv4Name, giao diện uint32_t);
void EnableAsciiIpv4 (Ptr stream, std :: string ipv4Name, uint32_t interface);

void EnableAsciiIpv4 (tiền tố std :: string, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr luồng, Ipv4InterfaceContainer c);

void EnableAsciiIpv4 (tiền tố std :: string, NodeContainer n);
void EnableAsciiIpv4 (Ptr luồng, NodeContainer n);

void EnableAsciiIpv4 (tiền tố std::string, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiIpv4 (Ptr stream, giao diện uint32_t nodeid, uint32_t);

void EnableAsciiIpv4All (tiền tố std :: string);
void EnableAsciiIpv4All (Ptr dòng);

Bạn được khuyến khích đọc Doxygen cho lớp học PcapAndAsciiHelperForIpv4 để tìm
chi tiết của các phương pháp này; nhưng tóm lại ...

Có số phương pháp truy tìm ascii nhiều gấp đôi so với pcap
truy tìm. Điều này là do, ngoài mô hình kiểu pcap nơi có dấu vết từ mỗi
cặp giao thức / giao diện duy nhất được ghi vào một tệp duy nhất, chúng tôi hỗ trợ một mô hình trong đó
thông tin theo dõi cho nhiều cặp giao thức / giao diện được ghi vào một tệp chung. Cái này
có nghĩa là -N - cơ chế tạo tên tập tin được thay thế
bằng cơ chế tham chiếu đến một tập tin chung; và số lượng phương thức API được tăng gấp đôi lên
cho phép tất cả các kết hợp.

Giống như trong việc theo dõi pcap, bạn có thể kích hoạt tính năng theo dõi ascii trên một giao thức/giao diện cụ thể
ghép nối bằng cách cung cấp một Ptr và một giao diện đến một BậtAscii phương pháp. Ví dụ,:

Ptr ipv4;
...
helper.EnableAsciiIpv4 ("tiền tố", ipv4, 1);

Trong trường hợp này, không có ngữ cảnh theo dõi nào được ghi vào tệp dấu vết ascii vì chúng sẽ
dư thừa. Hệ thống sẽ chọn tên tệp sẽ được tạo bằng cách sử dụng các quy tắc tương tự như
được mô tả trong phần pcap, ngoại trừ việc tệp sẽ có hậu tố ".tr" thay vì
".pcap".

Nếu bạn muốn bật tính năng theo dõi ascii trên nhiều giao diện và gửi tất cả dấu vết tới
một tệp duy nhất, bạn cũng có thể làm điều đó bằng cách sử dụng một đối tượng để tham chiếu đến một tệp duy nhất. Chúng tôi
đã có thứ gì đó tương tự như thế này trong ví dụ "cwnd" ở trên:

Ptr protocol4 = node1-> GetObject ();
Ptr protocol4 = node2-> GetObject ();
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (luồng, giao thức1, 1);
helper.EnableAsciiIpv4 (luồng, giao thức2, 1);

Trong trường hợp này, ngữ cảnh theo dõi được ghi vào tệp theo dõi ascii vì chúng được yêu cầu
để phân biệt dấu vết từ hai giao diện. Lưu ý rằng vì người dùng hoàn toàn
chỉ định tên tệp, chuỗi phải bao gồm ".tr" để thống nhất.

Bạn có thể kích hoạt tính năng theo dõi ascii trên một giao thức cụ thể bằng cách cung cấp std :: string
đại diện cho một chuỗi dịch vụ tên đối tượng thành một Kích hoạtPcap phương pháp. Các Ptr is
tra cứu từ chuỗi tên. Các trong tên tệp kết quả là ẩn vì
có sự tương ứng một-một giữa các phiên bản giao thức và nút. Ví dụ:

Names :: Add ("node1Ipv4" ...);
Names :: Add ("node2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("tiền tố", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("tiền tố", "node2Ipv4", 1);

Điều này sẽ dẫn đến hai tệp có tên "prefix-nnode1Ipv4-i1.tr" và
"prefix-nnode2Ipv4-i1.tr" với dấu vết cho từng giao diện trong tệp dấu vết tương ứng.
Vì tất cả các hàm EnableAscii đều bị quá tải để có một trình bao bọc luồng, bạn có thể
cũng sử dụng biểu mẫu đó:

Names :: Add ("node1Ipv4" ...);
Names :: Add ("node2Ipv4" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (luồng, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (luồng, "node2Ipv4", 1);

Điều này sẽ dẫn đến một tệp theo dõi duy nhất có tên là "trace-file-name.tr" chứa tất cả
các sự kiện theo dõi cho cả hai giao diện. Các sự kiện sẽ được phân biệt bằng bối cảnh theo dõi
dây.

Bạn có thể kích hoạt tính năng theo dõi ascii trên một tập hợp các cặp giao thức/giao diện bằng cách cung cấp một
Bộ chứa giao diện Ipv4. Đối với mỗi giao thức thuộc loại thích hợp (cùng loại được quản lý
bởi người trợ giúp thiết bị), tính năng theo dõi được bật cho giao diện tương ứng. Một lần nữa,
là ẩn vì có sự tương ứng một-một giữa mỗi giao thức và
nút của nó. Ví dụ,:

Các nút NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (các nút);
...
Ipv4AddressTrợ giúp ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer giao diện = ipv4.Assign (thiết bị);
...
...
helper.EnableAsciiIpv4 ("tiền tố", giao diện);

Điều này sẽ dẫn đến một số tệp dấu vết ascii được tạo, mỗi tệp theo sau
các -N -tôi quy ước .tr. Kết hợp tất cả các dấu vết thành một
một tệp được thực hiện tương tự như các ví dụ trên:

Các nút NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (các nút);
...
Ipv4AddressTrợ giúp ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer giao diện = ipv4.Assign (thiết bị);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (luồng, giao diện);

Bạn có thể kích hoạt tính năng theo dõi ascii trên một tập hợp các cặp giao thức/giao diện bằng cách cung cấp một
NútContainer. Cho mỗi Node trong NútContainer giao thức thích hợp được tìm thấy. Vì
mỗi giao thức, các giao diện của nó được liệt kê và việc theo dõi được kích hoạt trên kết quả
cặp. Ví dụ,:

nútContainer n;
...
helper.EnableAsciiIpv4 ("tiền tố", n);

Điều này sẽ dẫn đến một số tệp dấu vết ascii được tạo, mỗi tệp theo sau
các - - quy ước .tr. Kết hợp tất cả các dấu vết thành một
một tệp được thực hiện tương tự như các ví dụ trên:

Bạn cũng có thể kích hoạt tính năng theo dõi pcap trên cơ sở ID nút và ID thiết bị. Trong trường hợp này,
node-id được dịch sang một Ptr và giao thức thích hợp được tra cứu trong
nút. Giao thức và giao diện kết quả được sử dụng để chỉ định dấu vết kết quả
nguồn.:

helper.EnableAsciiIpv4 ("tiền tố", 21, 1);

Tất nhiên, các dấu vết có thể được kết hợp thành một tệp duy nhất như hình trên.

Cuối cùng, bạn có thể kích hoạt tính năng theo dõi ascii cho tất cả các giao diện trong hệ thống, với các giao diện được liên kết
giao thức có cùng loại với giao thức được quản lý bởi trình trợ giúp thiết bị.:

helper.EnableAsciiIpv4All ("tiền tố");

Điều này sẽ dẫn đến một số tệp theo dõi ascii được tạo, một tệp cho mỗi giao diện
trong hệ thống liên quan đến giao thức thuộc loại do người trợ giúp quản lý. Tất cả các tập tin này
sẽ làm theo -N -Tôi
vào một tệp duy nhất được thực hiện tương tự như các ví dụ trên.

Thăng thiên Truy tìm Dụng cụ Người giúp đỡ Tên tập tin Lựa chọn
Ngụ ý trong các mô tả phương pháp kiểu tiền tố ở trên là việc xây dựng hoàn chỉnh
tên tập tin theo phương pháp thực hiện. Theo quy ước, dấu vết ascii trong ns-3 hệ thống là
có dạng " - - .tr."

Như đã đề cập trước đó, mọi nút trong hệ thống sẽ có id nút do hệ thống gán.
Vì có sự tương ứng XNUMX-XNUMX giữa các giao thức và các nút nên chúng tôi sử dụng cho node-id
để xác định danh tính giao thức. Mọi giao diện trên một giao thức nhất định sẽ có
chỉ mục giao diện (còn được gọi đơn giản là giao diện) liên quan đến giao thức của nó. Theo mặc định,
sau đó, tệp theo dõi ascii được tạo do bật tính năng theo dõi trên thiết bị đầu tiên của
nút 21, sử dụng tiền tố "tiền tố", sẽ là "prefix-n21-i1.tr". Sử dụng tiền tố để
phân biệt nhiều giao thức trên mỗi nút.

Bạn luôn có thể sử dụng ns-3 dịch vụ tên đối tượng để làm cho điều này rõ ràng hơn. Ví dụ, nếu
bạn sử dụng dịch vụ tên đối tượng để gán tên "serverIpv4" cho giao thức trên nút
21, đồng thời chỉ định giao diện một, tên tệp dấu vết ascii thu được sẽ tự động
trở thành, "prefix-nserverIpv4-1.tr".

Truy tìm thực hiện chi tiết
Ngày Bộ sưu tập
Chương này mô tả Khung thu thập dữ liệu ns-3 (DCF), cung cấp
khả năng lấy dữ liệu được tạo bởi các mô hình trong trình mô phỏng, để thực hiện trực tuyến
giảm thiểu và xử lý dữ liệu, và điều chỉnh dữ liệu thô hoặc chuyển đổi thành các đầu ra khác nhau
định dạng.

Khung hiện tại hỗ trợ chạy ns-3 độc lập không phụ thuộc vào bất kỳ
điều khiển thực hiện chương trình. Các đối tượng do DCF cung cấp có thể được kết nối với ns-3 theo dõi
nguồn để cho phép xử lý dữ liệu.

Mã nguồn cho các lớp nằm trong thư mục src / stats.

Chương này được tổ chức như sau. Đầu tiên, tổng quan về kiến ​​trúc là
đã trình bày. Tiếp theo, những người trợ giúp cho các lớp này được trình bày; điều trị ban đầu này
nên cho phép sử dụng cơ bản khung thu thập dữ liệu cho nhiều trường hợp sử dụng. Người dùng
muốn sản xuất đầu ra ngoài phạm vi của những người trợ giúp hiện tại hoặc những người muốn tạo
các đối tượng thu thập dữ liệu của riêng họ, nên đọc phần còn lại của chương,
chi tiết về tất cả các loại đối tượng DCF cơ bản và cung cấp mã hóa cấp thấp
ví dụ.

Thiết kế
DCF bao gồm ba lớp cơ bản:

· Probe là một cơ chế để thiết bị và kiểm soát đầu ra của dữ liệu mô phỏng
được sử dụng để theo dõi các sự kiện thú vị. Nó tạo ra đầu ra dưới dạng một hoặc nhiều ns-3
nguồn gốc. Các đối tượng thăm dò được nối với một hoặc nhiều dấu vết bồn rửa (gọi là
Người sưu tầm), xử lý mẫu trực tuyến và chuẩn bị cho đầu ra.

· Collector sử dụng dữ liệu được tạo bởi một hoặc nhiều đối tượng Probe. Nó thực hiện
các biến đổi trên dữ liệu, chẳng hạn như chuẩn hóa, giảm thiểu và tính toán
thống kê cơ bản. Đối tượng bộ sưu tập không tạo ra dữ liệu được xuất trực tiếp bởi
ns-3 chạy; thay vào đó, chúng xuất dữ liệu xuôi dòng tới một loại đối tượng khác, được gọi là
Bộ tổng hợp, thực hiện chức năng đó. Thông thường, Người thu thập xuất dữ liệu của họ trong
cả dạng nguồn gốc, cho phép người thu thập được xâu chuỗi theo chuỗi.

· Bộ tổng hợp là điểm cuối của dữ liệu được thu thập bởi một mạng Đầu dò và Bộ thu thập.
Trách nhiệm chính của Người tổng hợp là thống nhất dữ liệu và
siêu dữ liệu, thành các định dạng đầu ra khác nhau, chẳng hạn như tệp văn bản thuần túy, tệp bảng tính hoặc
cơ sở dữ liệu.

Cả ba lớp này đều cung cấp khả năng tự động bật hoặc tắt
trong suốt một mô phỏng.

Bất kỳ độc lập nào ns-3 chạy mô phỏng sử dụng DCF thường sẽ tạo ra ít nhất một
thể hiện của mỗi trong ba lớp trên.
[image] Tổng quan về Khung thu thập dữ liệu.UNINDENT

Quy trình xử lý dữ liệu tổng thể được mô tả trong Ngày Bộ sưu tập Khung tổng quan.
Ở phía bên trái, một cuộc chạy ns-3 mô phỏng được mô tả. Trong quá trình chạy
mô phỏng, dữ liệu được tạo sẵn bởi các mô hình thông qua các nguồn theo dõi, hoặc thông qua các phương tiện khác.
Sơ đồ mô tả rằng các đầu dò có thể được kết nối với các nguồn theo dõi này để nhận dữ liệu
không đồng bộ, hoặc các đầu dò có thể thăm dò dữ liệu. Dữ liệu sau đó được chuyển đến một đối tượng thu thập
biến đổi dữ liệu. Cuối cùng, một bộ tổng hợp có thể được kết nối với các đầu ra của
bộ sưu tập, để tạo các lô, tệp hoặc cơ sở dữ liệu.
[image] Tổng hợp Khung thu thập dữ liệu.UNINDENT

Một biến thể trên hình trên được cung cấp trong Ngày Bộ sưu tập Khung tập hợp.
Hình thứ hai này minh họa rằng các đối tượng DCF có thể được liên kết với nhau theo cách
rằng các đối tượng xuôi dòng lấy đầu vào từ nhiều đối tượng ngược dòng. Tượng
về mặt khái niệm cho thấy rằng nhiều đầu dò có thể tạo ra đầu ra được đưa vào một
người thu tiền; như một ví dụ, một bộ sưu tập xuất ra một tỷ lệ của hai bộ đếm sẽ
thường thu được dữ liệu từng bộ đếm từ các đầu dò riêng biệt. Nhiều nhà sưu tập cũng có thể
nguồn cấp dữ liệu vào một trình tổng hợp duy nhất, (như tên gọi của nó) có thể thu thập một số dữ liệu
luồng để đưa vào một âm mưu, tệp hoặc cơ sở dữ liệu.

Ngày Bộ sưu tập Người giúp việc
Tính linh hoạt đầy đủ của khung thu thập dữ liệu được cung cấp bởi kết nối
của các đầu dò, bộ thu và bộ tổng hợp. Thực hiện tất cả các kết nối này dẫn đến
nhiều câu lệnh cấu hình trong chương trình người dùng. Để dễ sử dụng, một số điểm phổ biến nhất
các hoạt động có thể được kết hợp và đóng gói trong các hàm trợ giúp. Ngoài ra, một số
tuyên bố liên quan đến ns-3 nguồn theo dõi không có liên kết Python, do các hạn chế trong
các ràng buộc.

Ngày Bộ sưu tập Người giúp việc Giới thiệu chung
Trong phần này, chúng tôi cung cấp tổng quan về một số lớp trợ giúp đã được tạo để
dễ dàng cấu hình khung thu thập dữ liệu cho một số trường hợp sử dụng phổ biến. Các
trình trợ giúp cho phép người dùng hình thành các hoạt động phổ biến chỉ với một vài câu lệnh trong C ++ của họ hoặc
Các chương trình Python. Tuy nhiên, sự dễ sử dụng này có chi phí thấp hơn đáng kể
tính linh hoạt hơn so với cấu hình cấp thấp có thể cung cấp và sự cần thiết phải viết mã rõ ràng
hỗ trợ các loại Probe mới vào trình trợ giúp (để khắc phục sự cố được mô tả bên dưới).

Sự nhấn mạnh của các trình trợ giúp hiện tại là kiểm soát dữ liệu ra khỏi ns-3 theo dõi nguồn thành
lô gnuplot hoặc tệp văn bản, không có tùy chỉnh đầu ra hoặc thống kê ở mức độ cao
xử lý (ban đầu). Ngoài ra, việc sử dụng bị hạn chế đối với các loại đầu dò có sẵn trong
ns-3. Các phần sau của tài liệu này sẽ đi vào chi tiết hơn về cách tạo mới
Các loại thăm dò, cũng như thông tin chi tiết về việc kết nối các Đầu dò, Bộ sưu tập và Bộ tổng hợp lại với nhau
trong sự sắp xếp tùy chỉnh.

Cho đến nay, hai trình trợ giúp Thu thập dữ liệu đã được triển khai:

· Trình trợ giúp Gnuplot

· Trình trợ giúp tệp

Trình trợ giúp Gnuplot
GnuplotHelper là một lớp trợ giúp để tạo ra các tệp đầu ra được sử dụng để tạo gnuplots. Các
mục tiêu tổng thể là cung cấp khả năng cho người dùng nhanh chóng tạo các ô từ dữ liệu đã xuất
in ns-3 nguồn gốc. Theo mặc định, một lượng chuyển đổi dữ liệu tối thiểu được thực hiện;
mục tiêu là tạo ra các âm mưu với ít câu lệnh cấu hình (mặc định) như
có thể.

Trình trợ giúp Gnuplot Giới thiệu chung
GnuplotHelper sẽ tạo 3 tệp khác nhau ở cuối mô phỏng:

· Tệp dữ liệu gnuplot được phân tách bằng dấu cách

· Một tệp điều khiển gnuplot

· Một tập lệnh shell để tạo gnuplot

Có hai câu lệnh cấu hình cần thiết để tạo ra các lô. Người đầu tiên
câu lệnh cấu hình âm mưu (tên tệp, tiêu đề, chú giải và loại đầu ra, nơi đầu ra
nhập mặc định thành PNG nếu không xác định):

void ConfigurePlot (const std :: string & outputFileNameWithoutExtension,
const std :: string & title,
const std :: string & xLegend,
const std :: string & yLegend,
const std :: string & terminalType = ".png");

Câu lệnh thứ hai kết nối nguồn quan tâm theo dõi:

void PlotProbe (const std :: string & typeId,
const std :: string & path,
const std :: string & probeTraceSource,
const std :: string & title);

Các đối số như sau:

· TypeId: Cái ns-3 LoạiId của đầu dò

· Path: Đường dẫn trong ns-3 cấu hình không gian tên cho một hoặc nhiều nguồn theo dõi

· ProbeTraceSource: Đầu ra nào của đầu dò (bản thân nó là một nguồn theo dõi) nên được vẽ biểu đồ

· Title: Tiêu đề liên kết với (các) tập dữ liệu (trong chú giải gnuplot)

Một biến thể trên PlotProbe ở trên là chỉ định đối số tùy chọn thứ năm điều khiển
trong cốt truyện, khóa (chú giải) được đặt ở đâu.

Một ví dụ hoạt động đầy đủ (từ thứ bảy.cc) được hiển thị bên dưới:

// Tạo trình trợ giúp gnuplot.
Cốt truyện GnuplotHelperTrợ giúp;

// Cấu hình cốt truyện.
// Cấu hình cốt truyện. Đối số đầu tiên là tiền tố tên tệp
// cho các tệp đầu ra được tạo. Thứ hai, thứ ba và thứ tư
// các đối số lần lượt là nhãn tiêu đề, trục x và trục y
plotHelper.ConfigurePlot ("số gói-byte-thứ bảy",
"Số byte gói so với thời gian",
"Thời gian (Giây)",
"Số byte gói",
"png");

// Chỉ định loại thăm dò, đường dẫn nguồn theo dõi (trong không gian tên cấu hình) và
// thăm dò nguồn theo dõi đầu ra ("OutputBytes") để vẽ biểu đồ. Đối số thứ tư
// chỉ định tên của nhãn chuỗi dữ liệu trên biểu đồ. Cuối cùng
// đối số định dạng âm mưu bằng cách chỉ định nơi khóa sẽ được đặt.
cốt truyệnHelper.PlotProbe (probeType,
dấu vết,
"OutputBytes",
"Số byte gói",
GnuplotAggregator :: KEY_BELOW);

Trong ví dụ này, thăm dòTypedấu vết như sau (đối với IPv4):

probeType = "ns3 :: Ipv4PacketProbe";
tracePath = "/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx";

ProbeType là một tham số chính để trình trợ giúp này hoạt động. TypeId này phải được đăng ký
trong hệ thống và chữ ký trên bồn rửa dấu vết của Probe phải khớp với chữ ký của dấu vết
nguồn nó đang được nối vào. Các kiểu thăm dò được xác định trước cho một số kiểu dữ liệu
tương ứng với ns-3 các giá trị được theo dõi và một số chữ ký nguồn theo dõi khác như
nguồn theo dõi 'Tx' của ns3 :: Ipv4L3Protocol lớp học.

Lưu ý rằng đường dẫn nguồn theo dõi được chỉ định có thể chứa các ký tự đại diện. Trong trường hợp này, nhiều
tập dữ liệu được vẽ trên một ô; một cho mỗi đường dẫn phù hợp.

Đầu ra chính được tạo ra sẽ là ba tệp:

XNUMXth-pack-byte-count.dat
XNUMXth-pack-byte-count.plt
XNUMXth-packet-byte-count.sh

Tại thời điểm này, người dùng có thể chỉnh sửa thủ công tệp .plt để có thêm các tùy chỉnh hoặc
chỉ cần chạy nó qua gnuplot. Đang chạy sh XNUMXth-packet-byte-count.sh chỉ đơn giản là chạy cốt truyện
thông qua gnuplot, như hình dưới đây.
[image] Gnuplot 2-D được tạo bởi XNUMXth.cc Ví dụ..UNINDENT

Có thể thấy rằng các yếu tố chính (chú giải, tiêu đề, vị trí chú thích, xlabel, ylabel,
và đường dẫn cho dữ liệu) đều được đặt trên biểu đồ. Vì có hai trận đấu với
đường dẫn cấu hình được cung cấp, hai chuỗi dữ liệu được hiển thị:

· Packet Byte Count-0 tương ứng với / NodeList / 0 / $ ns3 :: Ipv4L3Protocol / Tx

· Packet Byte Count-1 tương ứng với / NodeList / 1 / $ ns3 :: Ipv4L3Protocol / Tx

Trình trợ giúp Gnuplot Cấu hìnhPlot
GnuplotHelper's ConfigurePlot () chức năng có thể được sử dụng để cấu hình các lô đất.

Nó có nguyên mẫu sau:

void ConfigurePlot (const std :: string & outputFileNameWithoutExtension,
const std :: string & title,
const std :: string & xLegend,
const std :: string & yLegend,
const std :: string & terminalType = ".png");

Nó có các đối số sau:

┌────────────────────────────────── ──────────────────┐
│ Đối số │ Mô tả │
├────────────────────────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Tên tệp liên quan đến gnuplot đến │
│ │ viết không có phần mở rộng. │
├────────────────────────────────── ──────────────────┤
│title │ Lô tiêu đề chuỗi để sử dụng cho │
│ │ âm mưu này. │
├────────────────────────────────── ──────────────────┤
│xLegend │ Truyền thuyết về x ngang │
Trục │ │. │
├────────────────────────────────── ──────────────────┤
│yLegend │ Truyền thuyết về y dọc │
Trục │ │. │
└────────────────────────────────── ──────────────────┘

│terminalType │ Chuỗi cài đặt loại đầu cuối cho │
│ │ đầu ra. Thiết bị đầu cuối mặc định │
Loại │ │ là "png". │
└────────────────────────────────── ──────────────────┘

GnuplotHelper's ConfigurePlot () chức năng cấu hình các thông số liên quan đến âm mưu cho điều này
gnuplot helper để nó sẽ tạo một tệp dữ liệu gnuplot được phân tách bằng dấu cách có tên
outputFileNameWithoutExtension + ".dat", một tệp điều khiển gnuplot có tên
outputFileNameWithoutExtension + ".plt" và một tập lệnh shell để tạo gnuplot có tên
outputFileNameWithoutExtension + ".sh".

Một ví dụ về cách sử dụng chức năng này có thể được xem trong thứ bảy.cc mã được mô tả ở trên
nơi nó đã được sử dụng như sau:

plotHelper.ConfigurePlot ("số gói-byte-thứ bảy",
"Số byte gói so với thời gian",
"Thời gian (Giây)",
"Số byte gói",
"png");

Trình trợ giúp Gnuplot Âm mưu thăm dò
GnuplotHelper's PlotProbe () hàm có thể được sử dụng để vẽ các giá trị được tạo ra bởi các đầu dò.

Nó có nguyên mẫu sau:

void PlotProbe (const std :: string & typeId,
const std :: string & path,
const std :: string & probeTraceSource,
const std :: string & title,
enum GnuplotAggregator :: KeyLocation keyLocation = GnuplotAggregator :: KEY_INSIDE);

Nó có các đối số sau:

┌─────────────────── ───┐
│ Đối số │ Mô tả │
├─────────────────── ───┤
│typeId │ ID loại cho đầu dò │
│ │ được tạo bởi người trợ giúp này. │
├─────────────────── ───┤
│path │ Định cấu hình đường dẫn để truy cập theo dõi │
│ │ nguồn. │
├─────────────────── ───┤
│probeTraceSource │ Nguồn theo dõi thăm dò tới │
│ │ truy cập. │
├─────────────────── ───┤
│title │ Tiêu đề được liên kết với │
│ │ tập dữ liệu này │
├─────────────────── ───┤
│keyLocation │ Vị trí của khoá trong │
│ │ âm mưu. Vị trí mặc định là │
│ │ bên trong. │
└─────────────────── ───┘

GnuplotHelper's PlotProbe () hàm vẽ một tập dữ liệu được tạo bằng cách nối ns-3
theo dõi nguồn bằng một thăm dò được tạo bởi người trợ giúp, sau đó vẽ biểu đồ các giá trị từ
probeTraceSource. Tập dữ liệu sẽ có tiêu đề được cung cấp và sẽ bao gồm
'newValue' tại mỗi dấu thời gian.

Nếu đường dẫn cấu hình có nhiều hơn một kết quả trùng khớp trong hệ thống vì có ký tự đại diện, thì
một tập dữ liệu cho mỗi trận đấu sẽ được vẽ biểu đồ. Tiêu đề tập dữ liệu sẽ được gắn với
các ký tự phù hợp cho từng ký tự đại diện trong đường dẫn cấu hình, được phân tách bằng dấu cách. Vì
ví dụ: nếu tiêu đề tập dữ liệu được đề xuất là chuỗi "byte" và có hai ký tự đại diện
trong đường dẫn, thì tiêu đề tập dữ liệu như "byte-0 0" hoặc "byte-12 9" sẽ có thể
nhãn cho các tập dữ liệu được vẽ.

Một ví dụ về cách sử dụng chức năng này có thể được xem trong thứ bảy.cc mã được mô tả ở trên
nơi nó đã được sử dụng (với sự thay thế biến) như sau:

plotHelper.PlotProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes",
"Số byte gói",
GnuplotAggregator :: KEY_BELOW);

Khác Các ví dụ
gnuplot Người giúp đỡ Ví dụ
Một ví dụ đơn giản hơn một chút so với thứ bảy.cc ví dụ có thể được tìm thấy trong
src / stats /amples / gnuplot-helper-example.cc. Gnuplot 2-D sau đây đã được tạo bằng
ví dụ.
[image] Gnuplot 2-D Được tạo bởi gnuplot-helper-example.cc Ví dụ..UNINDENT

Trong ví dụ này, có một đối tượng Emitter tăng bộ đếm của nó theo
Quá trình Poisson và sau đó phát ra giá trị của bộ đếm như một nguồn theo dõi.

Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", emitter);

Lưu ý rằng vì không có ký tự đại diện nào trong đường dẫn được sử dụng bên dưới, nên chỉ có 1 dòng dữ liệu là
được vẽ trong cốt truyện. Dòng dữ liệu duy nhất này trong biểu đồ được gắn nhãn đơn giản là "Đếm bộ phát",
không có hậu tố thừa giống như người ta sẽ xem liệu có ký tự đại diện trong đường dẫn hay không.

// Tạo trình trợ giúp gnuplot.
Cốt truyện GnuplotHelperTrợ giúp;

// Cấu hình cốt truyện.
plotHelper.ConfigurePlot ("gnuplot-helper-example",
"Đếm phát so với thời gian",
"Thời gian (Giây)",
"Đếm phát",
"png");

// Vẽ đồ thị các giá trị do đầu dò tạo ra. Con đường mà chúng tôi cung cấp
// giúp phân định nguồn gốc của dấu vết.
plotHelper.PlotProbe ("ns3 :: Uinteger32Probe",
"/ Names / Emitter / Counter",
"Đầu ra",
"Đếm phát",
GnuplotAggregator :: KEY_INSIDE);

Trình trợ giúp tệp
FileHelper là một lớp trợ giúp được sử dụng để đưa các giá trị dữ liệu vào một tệp. Mục tiêu tổng thể là
để cung cấp cho người dùng khả năng nhanh chóng tạo các tệp văn bản được định dạng từ dữ liệu được xuất
in ns-3 nguồn gốc. Theo mặc định, một lượng chuyển đổi dữ liệu tối thiểu được thực hiện;
mục tiêu là tạo tệp với ít câu lệnh cấu hình (mặc định) như
có thể.

Trình trợ giúp tệp Giới thiệu chung
FileHelper sẽ tạo 1 hoặc nhiều tệp văn bản ở cuối mô phỏng.

FileHelper có thể tạo 4 loại tệp văn bản khác nhau:

· Đã định dạng

· Không gian tách biệt (mặc định)

· Phân tách bằng dấu phẩy

· Tab được phân tách

Các tệp được định dạng sử dụng chuỗi định dạng kiểu C và hàm sprintf () để in
giá trị trong tệp đang được ghi.

Tệp văn bản sau có 2 cột giá trị được định dạng có tên
thứ bảy-gói-byte-đếm-0.txt đã được tạo bằng cách sử dụng thêm mã mới đã được thêm vào
nguyên ns-3 Mã của ví dụ hướng dẫn. Chỉ 10 dòng đầu tiên của tệp này được hiển thị
ở đây cho ngắn gọn.

Thời gian (Giây) = 1.000e + 00 Số byte gói = 40
Thời gian (Giây) = 1.004e + 00 Số byte gói = 40
Thời gian (Giây) = 1.004e + 00 Số byte gói = 576
Thời gian (Giây) = 1.009e + 00 Số byte gói = 576
Thời gian (Giây) = 1.009e + 00 Số byte gói = 576
Thời gian (Giây) = 1.015e + 00 Số byte gói = 512
Thời gian (Giây) = 1.017e + 00 Số byte gói = 576
Thời gian (Giây) = 1.017e + 00 Số byte gói = 544
Thời gian (Giây) = 1.025e + 00 Số byte gói = 576
Thời gian (Giây) = 1.025e + 00 Số byte gói = 544

...

Tệp văn bản khác nhau sau đây có 2 cột giá trị được định dạng có tên
thứ bảy-gói-byte-đếm-1.txt cũng đã được tạo bằng cách sử dụng cùng một mã mới đã được thêm vào
bản gốc ns-3 Mã của ví dụ hướng dẫn. Chỉ 10 dòng đầu tiên của tệp này được hiển thị
ở đây cho ngắn gọn.

Thời gian (Giây) = 1.002e + 00 Số byte gói = 40
Thời gian (Giây) = 1.007e + 00 Số byte gói = 40
Thời gian (Giây) = 1.013e + 00 Số byte gói = 40
Thời gian (Giây) = 1.020e + 00 Số byte gói = 40
Thời gian (Giây) = 1.028e + 00 Số byte gói = 40
Thời gian (Giây) = 1.036e + 00 Số byte gói = 40
Thời gian (Giây) = 1.045e + 00 Số byte gói = 40
Thời gian (Giây) = 1.053e + 00 Số byte gói = 40
Thời gian (Giây) = 1.061e + 00 Số byte gói = 40
Thời gian (Giây) = 1.069e + 00 Số byte gói = 40

...

Mã mới được thêm vào để tạo ra hai tệp văn bản ở bên dưới. Thêm chi tiết về
API này sẽ được đề cập trong phần sau.

Lưu ý rằng vì có 2 kết quả trùng khớp cho ký tự đại diện trong đường dẫn nên 2 tệp văn bản riêng biệt
đã được tạo. Tệp văn bản đầu tiên, được đặt tên là "0th-pack-byte-count-XNUMX.txt",
tương ứng với đối sánh ký tự đại diện với "*" được thay thế bằng "0". Tệp văn bản thứ hai,
được đặt tên là "1th-pack-byte-count-XNUMX.txt", tương ứng với kết hợp ký tự đại diện với
"*" được thay thế bằng "1". Ngoài ra, lưu ý rằng hàm gọi đến WriteProbe () sẽ đưa ra một
thông báo lỗi nếu không có kết quả phù hợp nào cho một đường dẫn có chứa các ký tự đại diện.

// Tạo trình trợ giúp tệp.
Trình trợ giúp tệp Trình trợ giúp tệp;

// Định cấu hình tệp được ghi.
fileHelper.ConfigureFile ("số lượng byte thứ bảy",
FileAggregator :: FORMATTED);

// Đặt nhãn cho tệp đầu ra được định dạng này.
fileHelper.Set2dFormat ("Thời gian (Giây) =% .3e \ tPacket Byte Count =% .0f");

// Ghi các giá trị do đầu dò tạo ra.
fileHelper.WriteProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes");

Trình trợ giúp tệp Cấu hình tập tin
FileHelper's ConfigureFile () có thể được sử dụng để cấu hình các tệp văn bản.

Nó có nguyên mẫu sau:

void ConfigureFile (const std :: string & outputFileNameWithoutExtension,
enum FileAggregator :: FileType fileType = FileAggregator :: SPACE_SEPARATED);

Nó có các đối số sau:

┌────────────────────────────────── ──────────────────┐
│ Đối số │ Mô tả │
├────────────────────────────────── ──────────────────┤
│outputFileNameWithoutExtension │ Tên tệp đầu ra để ghi │
│ │ không có phần mở rộng. │
├────────────────────────────────── ──────────────────┤
│fileType │ Loại tệp để ghi. │
│ │ loại tệp mặc định là khoảng trắng │
│ │ tách ra. │
└────────────────────────────────── ──────────────────┘

FileHelper's ConfigureFile () chức năng định cấu hình các thông số liên quan đến tệp văn bản cho
trình trợ giúp tệp để nó sẽ tạo tệp có tên outputFileNameWithoutExtension plus
thông tin bổ sung có thể có từ các đối sánh ký tự đại diện cộng với ".txt" với các giá trị được in dưới dạng
được chỉ định bởi fileType. Loại tệp mặc định được phân tách bằng dấu cách.

Một ví dụ về cách sử dụng chức năng này có thể được xem trong thứ bảy.cc mã được mô tả ở trên
nơi nó đã được sử dụng như sau:

fileHelper.ConfigureFile ("số lượng byte thứ bảy",
FileAggregator :: FORMATTED);

Trình trợ giúp tệp ViếtThăm Dò
FileHelper's WriteProbe () hàm có thể được sử dụng để ghi các giá trị được tạo bởi các đầu dò để
các tệp văn bản.

Nó có nguyên mẫu sau:

void WriteProbe (const std :: string & typeId,
const std :: string & path,
const std :: string & probeTraceSource);

Nó có các đối số sau:

┌─────────────────── ───┐
│ Đối số │ Mô tả │
├─────────────────── ───┤
│typeId │ ID loại cho đầu dò là │
│ │ được tạo ra. │
├─────────────────── ───┤
│path │ Định cấu hình đường dẫn để truy cập theo dõi │
│ │ nguồn. │
├─────────────────── ───┤
│probeTraceSource │ Nguồn theo dõi thăm dò tới │
│ │ truy cập. │
└─────────────────── ───┘

FileHelper's WriteProbe () hàm tạo các tệp văn bản đầu ra được tạo bằng cách nối
Nguồn theo dõi ns-3 với một đầu dò được tạo bởi người trợ giúp, sau đó ghi các giá trị từ
probeTraceSource. Tên tệp đầu ra sẽ có văn bản được lưu trữ trong biến thành viên
m_outputFileNameWithoutExtension cộng với ".txt" và sẽ bao gồm 'newValue' ở mỗi
dấu thời gian.

Nếu đường dẫn cấu hình có nhiều hơn một kết quả trùng khớp trong hệ thống vì có ký tự đại diện, thì
một tệp đầu ra cho mỗi trận đấu sẽ được tạo. Tên tệp đầu ra sẽ chứa
văn bản trong m_outputFileNameWithoutExtension cộng với các ký tự phù hợp cho mỗi
các ký tự đại diện trong đường dẫn cấu hình, được phân tách bằng dấu gạch ngang, cộng với ".txt". Ví dụ, nếu giá trị
trong m_outputFileNameWithoutExtension là chuỗi "gói-byte-đếm" và có hai
các ký tự đại diện trong đường dẫn, sau đó xuất ra các tên tệp như "pack-byte-count-0-0.txt" hoặc
"pack-byte-count-12-9.txt" có thể là tên cho các tệp sẽ được tạo.

Một ví dụ về cách sử dụng chức năng này có thể được xem trong thứ bảy.cc mã được mô tả ở trên
nơi nó đã được sử dụng như sau:

fileHelper.WriteProbe ("ns3 :: Ipv4PacketProbe",
"/ NodeList / * / $ ns3 :: Ipv4L3Protocol / Tx",
"OutputBytes");

Khác Các ví dụ
Tập tin Người giúp đỡ Ví dụ
Một ví dụ đơn giản hơn một chút so với thứ bảy.cc ví dụ có thể được tìm thấy trong
src / stats /amples / file-helper-example.cc. Ví dụ này chỉ sử dụng FileHelper.

Tệp văn bản sau có 2 cột giá trị được định dạng có tên tệp-helper-example.txt
đã được tạo bằng cách sử dụng ví dụ. Chỉ 10 dòng đầu tiên của tệp này được hiển thị ở đây cho
sự ngắn gọn.

Thời gian (Giây) = 0.203 Đếm = 1
Thời gian (Giây) = 0.702 Đếm = 2
Thời gian (Giây) = 1.404 Đếm = 3
Thời gian (Giây) = 2.368 Đếm = 4
Thời gian (Giây) = 3.364 Đếm = 5
Thời gian (Giây) = 3.579 Đếm = 6
Thời gian (Giây) = 5.873 Đếm = 7
Thời gian (Giây) = 6.410 Đếm = 8
Thời gian (Giây) = 6.472 Đếm = 9
...

Trong ví dụ này, có một đối tượng Emitter tăng bộ đếm của nó theo
Quá trình Poisson và sau đó phát ra giá trị của bộ đếm như một nguồn theo dõi.

Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", emitter);

Lưu ý rằng vì không có ký tự đại diện nào trong đường dẫn được sử dụng bên dưới, nên chỉ có 1 tệp văn bản là
tạo. Tệp văn bản duy nhất này được đặt tên đơn giản là "file-helper-example.txt", không có thêm
các hậu tố như bạn sẽ thấy nếu có các ký tự đại diện trong đường dẫn.

// Tạo trình trợ giúp tệp.
Trình trợ giúp tệp Trình trợ giúp tệp;

// Định cấu hình tệp được ghi.
fileHelper.ConfigureFile ("file-helper-example",
FileAggregator :: FORMATTED);

// Đặt nhãn cho tệp đầu ra được định dạng này.
fileHelper.Set2dFormat ("Thời gian (Giây) =% .3e \ tCount =% .0f");

// Ghi các giá trị do đầu dò tạo ra. Con đường mà chúng tôi
// cung cấp giúp phân định nguồn gốc của dấu vết.
fileHelper.WriteProbe ("ns3 :: Uinteger32Probe",
"/ Names / Emitter / Counter",
"Đầu ra");

Phạm vi Hạn chế
Hiện tại, chỉ những Đầu dò này đã được triển khai và kết nối với GnuplotHelper và
vào FileHelper:

· Đầu dò Boolean

· Đầu dò đôi

· Uinteger8Probe

· Uinteger16Probe

· Uinteger32Probe

· Thời gian thăm dò

· Đầu dò gói

· Ứng dụngPacketProbe

· Ipv4PacketProbe

Do đó, những đầu dò này là TypeIds duy nhất có sẵn để sử dụng trong PlotProbe ()
WriteProbe ().

Trong một vài phần tiếp theo, chúng tôi sẽ đề cập đến từng loại đối tượng cơ bản (Probe, Collector,
và Aggregator) chi tiết hơn và chỉ ra cách chúng có thể được kết nối với nhau bằng cách sử dụng
API cấp thấp hơn.

Đầu dò
Phần này trình bày chi tiết các chức năng được cung cấp bởi lớp Probe cho một ns-3
và đưa ra các ví dụ về cách viết mã chúng trong một chương trình. Phần này có nghĩa là
người dùng quan tâm đến việc phát triển mô phỏng với ns-3 công cụ và sử dụng Dữ liệu
Khung Bộ sưu tập, trong đó lớp Probe là một phần, để tạo đầu ra dữ liệu với
kết quả mô phỏng của họ.

Probe Giới thiệu chung
Một đối tượng Probe được cho là được kết nối với một biến từ mô phỏng có giá trị
trong suốt quá trình thử nghiệm có liên quan đến người dùng. Probe sẽ ghi lại những gì đã
các giá trị được giả định bởi biến trong suốt quá trình mô phỏng và chuyển dữ liệu đó sang một
thành viên của Khung thu thập dữ liệu. Mặc dù nó nằm ngoài phạm vi của phần này để
thảo luận về những gì sẽ xảy ra sau khi Probe tạo ra đầu ra của nó, có thể nói rằng, bằng cách
khi kết thúc mô phỏng, người dùng sẽ có thông tin chi tiết về những giá trị
được lưu trữ bên trong biến đang được thăm dò trong quá trình mô phỏng.

Thông thường, một Probe được kết nối với một ns-3 nguồn truy xuất. Theo cách này, bất cứ khi nào
nguồn theo dõi xuất ra một giá trị mới, Probe tiêu thụ giá trị đó (và xuất nó xuống dòng
đến một đối tượng khác thông qua nguồn theo dõi của chính nó).

Probe có thể được coi như một bộ lọc các nguồn theo dõi. Những lý do chính cho
có thể kết nối với Probe thay vì trực tiếp đến nguồn theo dõi như sau:

· Các đầu dò có thể được bật và tắt động trong quá trình mô phỏng với các lệnh gọi tới Cho phép()
Vô hiệu hóa(). Ví dụ: việc xuất dữ liệu có thể bị tắt trong
giai đoạn khởi động mô phỏng.

· Đầu dò có thể thực hiện các hoạt động trên dữ liệu để trích xuất các giá trị từ phức tạp hơn
cấu trúc; ví dụ: xuất ra giá trị kích thước gói từ ns3 :: Packet đã nhận.

· Probe đăng ký tên trong không gian tên ns3 :: Config (sử dụng Tên :: Thêm ()) để khác
các đối tượng có thể tham chiếu đến chúng.

· Probe cung cấp một phương thức tĩnh cho phép một người điều khiển một Probe theo tên, chẳng hạn như
những gì được thực hiện trong ns2measure [Cic06]

Stat :: put ("my_metric", ID, sample);

Tương đương ns-3 của mã ns2measure ở trên là, ví dụ:

DoubleProbe :: SetValueByPath ("/ path / to / probe", mẫu);

Sáng tạo
Lưu ý rằng không thể tạo đối tượng lớp cơ sở Probe vì nó là một cơ sở trừu tượng
lớp, tức là nó có các chức năng ảo thuần túy chưa được thực hiện. Một đối tượng của
gõ DoubleProbe, là một lớp con của lớp Probe, sẽ được tạo ở đây để hiển thị
Những gì cần phải được thực hiện.

Người ta khai báo DoubleProbe trong bộ nhớ động bằng cách sử dụng lớp con trỏ thông minh (Ptr ). Đến
tạo DoubleProbe trong bộ nhớ động với các con trỏ thông minh, người ta chỉ cần gọi
ns-3 phương pháp CreateObject ():

Ptr myprobe = CreateObject ();

Khai báo ở trên tạo DoubleProbes bằng cách sử dụng các giá trị mặc định cho các thuộc tính của nó.
Có bốn thuộc tính trong lớp DoubleProbe; hai trong đối tượng lớp cơ sở
DataCollectionObject và hai trong lớp cơ sở Probe:

· "Tên" (DataCollectionObject), một StringValue

· "Đã bật" (DataCollectionObject), một BooleanValue

· "Bắt đầu" (Probe), Giá trị thời gian

· "Dừng" (Probe), Giá trị thời gian

Người ta có thể đặt các thuộc tính như vậy khi tạo đối tượng bằng cách sử dụng phương pháp sau:

Ptr myprobe = CreateObjectWithAttributes (
"Tên", StringValue ("myprobe"),
"Đã bật", BooleanValue (sai),
"Start", TimeValue (Giây (100.0)),
"Dừng", TimeValue (Giây (1000.0)));

Bắt đầu và Dừng là các biến Thời gian xác định khoảng thời gian hoạt động của Đầu dò. Các
Probe sẽ chỉ xuất dữ liệu nếu thời gian hiện tại của Mô phỏng nằm trong thời gian đó
khoảng thời gian. Giá trị thời gian đặc biệt 0 giây cho Dừng sẽ vô hiệu hóa thuộc tính này (tức là
giữ Probe ở trạng thái bật cho toàn bộ mô phỏng). Đã bật là cờ bật Probe hoặc
tắt, và phải được đặt thành true để Probe xuất dữ liệu. Tên là tên của đối tượng
trong khuôn khổ DCF.

Nhập khẩu xuất khẩu dữ liệu
ns-3 các nguồn theo dõi được đánh máy mạnh mẽ, vì vậy các cơ chế để kết nối Đầu dò với một dấu vết
nguồn và để xuất dữ liệu thuộc về các lớp con của nó. Ví dụ, mặc định
phân phối ns-3 cung cấp một DoubleProbe lớp được thiết kế để kết nối với một dấu vết
nguồn xuất một giá trị kép. Tiếp theo, chúng tôi sẽ trình bày chi tiết về hoạt động của DoubleProbe và
sau đó thảo luận về cách người dùng có thể xác định các lớp Probe khác.

thăm dò kép Giới thiệu chung
DoubleProbe kết nối với một giá trị kép ns-3 nguồn theo dõi, và chính nó xuất một
giá trị kép khác nhau ns-3 nguồn truy xuất.

Đoạn mã sau đây, được rút ra từ src / stats /amples / double-probe-example.cc, cho thấy cơ bản
hoạt động của hệ thống ống nước DoubleProbe thành một mô phỏng, nơi nó đang thăm dò Bộ đếm
được xuất bởi một đối tượng emitter (class Emitter).

Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", emitter);
...

Ptr probe1 = CreateObject ();

// Kết nối đầu dò với Bộ đếm của bộ phát
bool connect = probe1-> ConnectByObject ("Bộ đếm", emitter);

Đoạn mã sau đang thăm dò cùng một Bộ đếm được xuất bởi cùng một đối tượng bộ phát. Cái này
DoubleProbe, tuy nhiên, đang sử dụng một đường dẫn trong không gian tên cấu hình để tạo
sự liên quan. Lưu ý rằng bộ phát đã đăng ký chính nó trong không gian tên cấu hình sau
Nó đã được tạo ra; nếu không, ConnectByPath sẽ không hoạt động.

Ptr probe2 = CreateObject ();

// Lưu ý, không có giá trị trả lại nào được kiểm tra ở đây
probe2-> ConnectByPath ("/ Tên / Bộ phát / Bộ đếm");

DoubleProbe tiếp theo được hiển thị được hiển thị bên dưới sẽ có giá trị được đặt bằng cách sử dụng đường dẫn của nó trong
không gian tên cấu hình. Lưu ý rằng lần này DoubleProbe tự đăng ký trong
không gian tên cấu hình sau khi nó được tạo.

Ptr probe3 = CreateObject ();
probe3-> SetName ("StaticallyAccessedProbe");

// Chúng ta phải thêm nó vào cơ sở dữ liệu cấu hình
Names :: Add ("/ Names / Probe", probe3-> GetName (), probe3);

Hàm Count () của emitter hiện có thể đặt giá trị cho DoubleProbe này là
sau:

làm mất hiệu lực
Bộ phát :: Đếm (vô hiệu)
{
...
m_counter + = 1.0;
DoubleProbe :: SetValueByPath ("/ Names / StaticallyAccessedProbe", m_counter);
...
}

Ví dụ trên cho thấy cách mã gọi Probe không cần phải có
tham chiếu đến Probe, nhưng có thể định hướng cài đặt giá trị thông qua không gian tên Cấu hình.
Điều này tương tự về chức năng với Thống kê :: Đặt phương pháp được giới thiệu bởi giấy ns2measure
[Cic06] và cho phép người dùng tạm thời chèn các câu lệnh thăm dò như printf báo cáo
trong hiện tại ns-3 các mô hình. Lưu ý rằng để có thể sử dụng DoubleProbe trong này
ví dụ như thế này, 2 điều là cần thiết:

1. tệp tiêu đề mô-đun thống kê đã được bao gồm trong tệp .cc mẫu

2. ví dụ được thực hiện phụ thuộc vào mô-đun thống kê trong tệp wscript của nó.

Những việc tương tự cần được thực hiện để thêm các Đầu dò khác ở những nơi khác trong ns-3
cơ sở mã.

Các giá trị cho DoubleProbe cũng có thể được đặt bằng cách sử dụng hàm DoubleProbe :: SetValue (),
trong khi các giá trị cho DoubleProbe có thể được nhận bằng cách sử dụng hàm
DoubleProbe :: GetValue ().

DoubleProbe xuất các giá trị kép trong nguồn theo dõi "Đầu ra" của nó; một đối tượng hạ lưu
có thể kết nối một bồn rửa theo dõi (NotifyViaProbe) vào điều này như sau:

connect = probe1-> TraceConnect ("Đầu ra", probe1-> GetName (), MakeCallback (& ​​NotifyViaProbe));

Khác tàu thăm dò
Bên cạnh DoubleProbe, các Đầu dò sau cũng có sẵn:

· Uinteger8Probe kết nối với một ns-3 nguồn theo dõi xuất một uint8_t.

· Uinteger16Probe kết nối với một ns-3 nguồn theo dõi xuất một uint16_t.

· Uinteger32Probe kết nối với một ns-3 nguồn theo dõi xuất một uint32_t.

· PacketProbe kết nối với một ns-3 nguồn theo dõi xuất một gói.

· ApplicationPacketProbe kết nối với một ns-3 nguồn theo dõi xuất một gói và một ổ cắm
địa chỉ nhà.

· Ipv4PacketProbe kết nối với một ns-3 nguồn theo dõi xuất một gói, một đối tượng IPv4 và
một giao diện.

Tạo người mới Probe loại
Để tạo một loại Probe mới, bạn cần thực hiện các bước sau:

· Đảm bảo rằng lớp Probe mới của bạn có nguồn gốc từ lớp cơ sở Probe.

· Đảm bảo rằng các chức năng ảo thuần túy mà lớp Probe mới của bạn kế thừa từ
Lớp cơ sở thăm dò được thực hiện.

· Tìm một lớp Probe hiện có sử dụng nguồn theo dõi gần loại nhất với
loại nguồn theo dõi mà Probe của bạn sẽ sử dụng.

· Sao chép tệp tiêu đề (.h) và tệp triển khai (.cc) của lớp Probe hiện có thành hai
các tệp mới có tên phù hợp với Probe mới của bạn.

· Thay thế các kiểu, đối số và biến trong các tệp đã sao chép bằng
gõ cho Probe của bạn.

· Thực hiện các sửa đổi cần thiết để làm cho mã biên dịch và làm cho nó hoạt động như bạn muốn
như.

Các ví dụ
Hai ví dụ sẽ được thảo luận chi tiết ở đây:

· Ví dụ về Double Probe

· Ví dụ về lô gói IPv4

Kép Probe Ví dụ
Ví dụ về thăm dò kép đã được thảo luận trước đây. Chương trình ví dụ có thể được tìm thấy
in src / stats /amples / double-probe-example.cc. Để tóm tắt những gì xảy ra trong chương trình này,
có một bộ phát xuất một bộ đếm tăng dần theo một quy trình Poisson.
Đặc biệt, hai cách phát ra dữ liệu được hiển thị:

1. thông qua một biến đã theo dõi được nối với một Probe:

TracedValue m_counter; // thông thường đây sẽ là kiểu số nguyên

2. thông qua một bộ đếm có giá trị được đăng lên một Đầu dò thứ hai, được tham chiếu bởi tên của nó trong
hệ thống cấu hình:

làm mất hiệu lực
Bộ phát :: Đếm (vô hiệu)
{
NS_LOG_FUNCTION (cái này);
NS_LOG_DEBUG ("Đang đếm" << Simulator :: Now () .GetSeconds ());
m_counter + = 1.0;
DoubleProbe :: SetValueByPath ("/ Names / StaticallyAccessedProbe", m_counter);
Simulator :: Schedule (Giây (m_var-> GetValue ()), & Emitter :: Count, this);
}

Hãy xem xét Probe kỹ hơn. Các đầu dò có thể nhận các giá trị của chúng trong một bội số
cách:

1. bằng cách Probe truy cập trực tiếp vào nguồn theo dõi và kết nối bồn rửa theo dõi với nó

2. bằng cách Probe truy cập nguồn theo dõi thông qua không gian tên cấu hình và kết nối
dấu vết chìm vào nó

3. bằng mã gọi một cách rõ ràng là Probe's Đặt giá trị() phương pháp

4. bằng mã gọi một cách rõ ràng SetValueByPath
("/ path / through / Config / namespace", ...)

Hai kỹ thuật đầu tiên được cho là phổ biến nhất. Cũng trong ví dụ,
nối một hàm gọi lại bình thường được hiển thị, như thường được thực hiện trong ns-3. Điều này
hàm callback không được liên kết với đối tượng Probe. Chúng tôi sẽ gọi trường hợp này là 0) bên dưới.

// Đây là một hàm để kiểm tra việc nối một hàm thô với nguồn theo dõi
làm mất hiệu lực
NotifyViaTraceSource (std :: string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context:" << context << "old" << oldVal << "new" << newVal);
}

Đầu tiên, bộ phát cần được thiết lập:

Ptr emitter = CreateObject ();
Names :: Add ("/ Names / Emitter", emitter);

// Đối tượng Emitter không được liên kết với nút ns-3, vì vậy
// nó sẽ không tự động bắt đầu, vì vậy chúng ta cần tự làm điều này
Trình mô phỏng :: Lịch biểu (Giây (0.0), & Bộ phát :: Bắt đầu, bộ phát);

Các DoubleProbe khác nhau tương tác với bộ phát trong ví dụ như hình dưới đây.

Trường hợp 0):

// Bên dưới hiển thị chức năng điển hình mà không cần thăm dò
// (kết nối một hàm chìm với một nguồn theo dõi)
//
connect = emitter-> TraceConnect ("Bộ đếm", "ngữ cảnh mẫu", MakeCallback (& ​​NotifyViaTraceSource));
NS_ASSERT_MSG (được kết nối, "Nguồn theo dõi không được kết nối");

trường hợp 1):

//
// Probe1 sẽ được nối trực tiếp với đối tượng nguồn theo dõi Emitter
//

// probe1 sẽ được nối với nguồn theo dõi Emitter
Ptr probe1 = CreateObject ();
// tên của đầu dò có thể đóng vai trò là ngữ cảnh của nó trong quá trình truy tìm
probe1-> SetName ("ObjectProbe");

// Kết nối đầu dò với Bộ đếm của bộ phát
kết nối = probe1-> ConnectByObject ("Bộ đếm", emitter);
NS_ASSERT_MSG (đã kết nối, "Nguồn theo dõi không được kết nối với đầu dò1");

trường hợp 2):

//
// Probe2 sẽ được nối với đối tượng nguồn theo dõi Emitter bằng
// truy cập nó bằng tên đường dẫn trong cơ sở dữ liệu Cấu hình
//

// Tạo một thăm dò tương tự khác; điều này sẽ kết nối thông qua một đường dẫn Cấu hình
Ptr probe2 = CreateObject ();
probe2-> SetName ("PathProbe");

// Lưu ý, không có giá trị trả lại nào được kiểm tra ở đây
probe2-> ConnectByPath ("/ Tên / Bộ phát / Bộ đếm");

trường hợp 4) (trường hợp 3 không được hiển thị trong ví dụ này):

//
// Probe3 sẽ được gọi bởi bộ phát trực tiếp thông qua
// phương thức tĩnh SetValueByPath ().
//
Ptr probe3 = CreateObject ();
probe3-> SetName ("StaticallyAccessedProbe");
// Chúng ta phải thêm nó vào cơ sở dữ liệu cấu hình
Names :: Add ("/ Names / Probe", probe3-> GetName (), probe3);

Và cuối cùng, ví dụ cho thấy cách các đầu dò có thể được nối để tạo ra đầu ra:

// Bản thân đầu dò sẽ tạo ra đầu ra. Bối cảnh mà chúng tôi cung cấp
// với thăm dò này (trong trường hợp này là tên thăm dò) sẽ giúp phân biệt
// nguồn của dấu vết
kết nối = probe3-> TraceConnect ("Đầu ra",
"/ Tên / Đầu dò / StaticallyAccessedProbe / Đầu ra",
MakeCallback (& ​​NotifyViaProbe));
NS_ASSERT_MSG (được kết nối, "Nguồn theo dõi không .. được kết nối với Đầu ra của đầu dò 3");

Lệnh gọi lại sau được nối với Probe trong ví dụ này cho các mục đích minh họa;
thông thường, Probe sẽ được nối với một đối tượng Collector.

// Đây là một hàm để kiểm tra việc nối nó với đầu ra của đầu dò
làm mất hiệu lực
NotifyViaProbe (std :: string context, double oldVal, double newVal)
{
NS_LOG_DEBUG ("context:" << context << "old" << oldVal << "new" << newVal);
}

IPv4 Gói Âm mưu Ví dụ
Ví dụ về âm mưu gói IPv4 dựa trên ví dụ thứ năm.cc từ ns-3 Hướng dẫn. Nó
có thể được tìm thấy trong src / stats /amples / ipv4-packet-plot-example.cc.

nút 0 nút 1
+ ---------------- + + ---------------- +
| ns-3TCP | | ns-3TCP |
+ ---------------- + + ---------------- +
| 10.1.1.1 | | 10.1.1.2 |
+ ---------------- + + ---------------- +
| điểm đến điểm | | điểm đến điểm |
+ ---------------- + + ---------------- +
| |
+ --------------------- +

Chúng ta sẽ chỉ xem xét Probe, vì nó minh họa rằng Probe cũng có thể giải nén các giá trị từ
cấu trúc (trong trường hợp này là các gói) và báo cáo các giá trị đó dưới dạng đầu ra nguồn theo dõi, thay vì
hơn là chỉ chuyển qua cùng một loại dữ liệu.

Có những khía cạnh khác của ví dụ này sẽ được giải thích sau trong tài liệu.
Hai loại dữ liệu được xuất ra là chính gói tin (Đầu ra) và một số
số byte trong gói (Đầu raByte).

loạiId
Ipv4PacketProbe :: GetTypeId ()
{
static TypeId tid = TypeId ("ns3 :: Ipv4PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ("Đầu ra",
"Gói cộng với đối tượng và giao diện IPv4 của nó đóng vai trò là đầu ra cho đầu dò này",
MakeTraceSourceAccessor (& Ipv4PacketProbe :: m_output))
.AddTraceSource ("OutputBytes",
"Số byte trong gói",
MakeTraceSourceAccessor (& Ipv4PacketProbe :: m_outputBytes))
;
trả lại tid;
}

Khi bộ theo dõi của Probe nhận được một gói tin, nếu Probe được kích hoạt, thì nó sẽ xuất ra
gói trên nó Đầu ra nguồn theo dõi, nhưng nó cũng sẽ xuất ra số byte trên
Đầu raByte nguồn truy xuất.

làm mất hiệu lực
Ipv4PacketProbe :: TraceSink (Ptr gói, Ptr giao diện ipv4, uint4_t)
{
NS_LOG_FUNCTION (this << gói << ipv4 << giao diện);
nếu (Đã bật ())
{
m_packet = gói tin;
m_ipv4 = ipv4;
m_interface = giao diện;
m_output (gói tin, ipv4, giao diện);

uint32_t packetSizeNew = pack-> GetSize ();
m_outputBytes (m_packetSizeOld, packetSizeNew);
m_packetSizeOld = packSizeNew;
}
}

dự án
[Cic06]
Claudio Cicconetti, Enzo Mingozzi, Giovanni Stea, "Khung tích hợp cho
Cho phép thu thập dữ liệu hiệu quả và phân tích thống kê với ns2, Hội thảo về
ns-2 (WNS2), Pisa, Ý, tháng 2006 năm XNUMX.

Người sưu tầm
Phần này là trình giữ chỗ để trình bày chi tiết các chức năng được cung cấp bởi Bộ sưu tập
lớp đến một ns-3 và đưa ra các ví dụ về cách viết mã chúng trong một chương trình.

Lưu ý: Kể từ ns-3.18, Collectors vẫn đang được phát triển và chưa được cung cấp như một phần
của khuôn khổ.

Bộ tổng hợp
Phần này trình bày chi tiết các chức năng được cung cấp bởi lớp Aggregator cho một ns-3
mô phỏng. Phần này dành cho những người dùng quan tâm đến việc phát triển mô phỏng với
ns-3 và sử dụng Khung thu thập dữ liệu, trong đó lớp Aggregator là
một phần, để tạo đầu ra dữ liệu với kết quả mô phỏng của họ.

Bộ tổng hợp Giới thiệu chung
Một đối tượng Aggregator phải được kết nối với một hoặc nhiều nguồn theo dõi để
nhận đầu vào. Trang tổng hợp là điểm cuối của dữ liệu được thu thập bởi mạng lưới
Đầu dò và Bộ thu trong quá trình mô phỏng. Công việc của Người tổng hợp là thực hiện những
và chuyển đổi chúng thành định dạng đầu ra cuối cùng, chẳng hạn như tệp văn bản thuần túy,
tệp bảng tính, ô hoặc cơ sở dữ liệu.

Thông thường, một bộ tổng hợp được kết nối với một hoặc nhiều Bộ sưu tập. Theo cách này, bất cứ khi nào
nguồn theo dõi của Người thu thập xuất giá trị mới, Người tổng hợp có thể xử lý giá trị để
rằng nó có thể được sử dụng ở định dạng đầu ra cuối cùng, nơi các giá trị dữ liệu sẽ nằm sau
mô phỏng.

Lưu ý những điều sau về Aggregators:

· Bộ tổng hợp có thể được bật và tắt động trong quá trình mô phỏng với các lệnh gọi tới
Cho phép()Vô hiệu hóa(). Ví dụ: tính năng tổng hợp dữ liệu có thể bị tắt trong
giai đoạn khởi động mô phỏng, có nghĩa là những giá trị đó sẽ không được đưa vào
phương tiện đầu ra.

· Người tổng hợp nhận dữ liệu từ Người thu thập thông qua các cuộc gọi lại. Khi một Bộ sưu tập được liên kết
cho một trình tổng hợp, một cuộc gọi tới TraceConnect được thực hiện để thiết lập dấu vết của Aggregator
phương thức chìm dưới dạng một cuộc gọi lại.

Đến nay, hai Trang tổng hợp đã được triển khai:

· Công cụ tổng hợp Gnuplot

· Trình tổng hợp tệp

Trình tổng hợp Gnuplot
GnuplotAggregator tạo ra các tệp đầu ra được sử dụng để tạo gnuplot.

GnuplotAggregator sẽ tạo 3 tệp khác nhau ở cuối mô phỏng:

· Tệp dữ liệu gnuplot được phân tách bằng dấu cách

· Một tệp điều khiển gnuplot

· Một tập lệnh shell để tạo gnuplot

Sáng tạo
Một đối tượng kiểu GnuplotAggregator sẽ được tạo ở đây để hiển thị những gì cần phải làm.

Người ta khai báo một GnuplotAggregator trong bộ nhớ động bằng cách sử dụng lớp con trỏ thông minh
(Ptr ). Để tạo GnuplotAggregator trong bộ nhớ động với con trỏ thông minh, bạn chỉ cần
cần gọi cho ns-3 phương pháp CreateObject (). Đoạn mã sau từ
src / stats /amples / gnuplot-aggregator-example.cc chỉ cách làm điều này:

string fileNameWithoutExtension = "gnuplot-integration";

// Tạo một trình tổng hợp.
Ptr người tổng hợp =
CreateObject (fileNameWithoutExtension);

Đối số đầu tiên cho hàm tạo, fileNameWithoutExtension, là tên của
gnuplot tệp liên quan để viết không có phần mở rộng. GnuplotAggregator này sẽ tạo
tệp dữ liệu gnuplot được phân tách bằng dấu cách có tên "gnuplot-integration.dat", một tệp điều khiển gnuplot
được đặt tên là "gnuplot-integration.plt" và một tập lệnh shell để tạo gnuplot có tên +
"gnuplot-aggregator.sh".

Gnuplot được tạo có thể có khóa của nó ở 4 vị trí khác nhau:

· Không có chìa khóa

· Chìa khóa bên trong cốt truyện (mặc định)

· Chìa khóa phía trên cốt truyện

· Chìa khóa bên dưới cốt truyện

Các giá trị enum vị trí khóa gnuplot sau đây được phép chỉ định vị trí của khóa:

enum Vị trí khóa {
KHÔNG CÓ,
KEY_INSIDE,
KEY_ABOVE,
KEY_DƯỚI ĐÂY
};

Nếu bạn muốn có khóa bên dưới thay vì vị trí mặc định của bên trong, thì
bạn có thể làm như sau.

tổng hợp-> SetKeyLocation (GnuplotAggregator :: KEY_BELOW);

Các ví dụ
Một ví dụ sẽ được thảo luận chi tiết ở đây:

· Ví dụ về công cụ tổng hợp Gnuplot

gnuplot Bộ tổng hợp Ví dụ
Có thể tìm thấy một ví dụ thực hiện GnuplotAggregator trong
src / stats /amples / gnuplot-aggregator-example.cc.

Gnuplot 2-D sau đây đã được tạo bằng cách sử dụng ví dụ.
[image] Gnuplot 2-D được tạo bởi gnuplot-aggregator-example.cc Ví dụ..UNINDENT

Đoạn mã từ ví dụ này cho thấy cách tạo GnuplotAggregator như đã được thảo luận
ở trên.

vô hiệu Create2dPlot ()
{
sử dụng namespace std;

string fileNameWithoutExtension = "gnuplot-integration";
string plotTitle = "Gnuplot Aggregator Plot";
string plotXAxisHeading = "Thời gian (giây)";
string plotYAxisHeading = "Giá trị kép";
string plotDatasetLabel = "Giá trị dữ liệu";
string datasetContext = "Dataset / Context / String";

// Tạo một trình tổng hợp.
Ptr người tổng hợp =
CreateObject (fileNameWithoutExtension);

Các thuộc tính GnuplotAggregator khác nhau được đặt bao gồm tập dữ liệu 2-D sẽ là
có âm mưu.

// Đặt thuộc tính của trình tổng hợp.
tổng hợp-> SetTerminal ("png");
bộ tổng hợp-> SetTitle (plotTitle);
tập hợp-> SetLegend (plotXAxisHeading, plotYAxisHeading);

// Thêm tập dữ liệu vào trình tổng hợp.
tập hợp-> Add2dDataset (datasetContext, plotDatasetLabel);

// bộ tổng hợp phải được bật
bộ tổng hợp-> Enable ();

Tiếp theo, các giá trị 2-D được tính toán và mỗi giá trị được ghi riêng vào
GnuplotAggregator bằng cách sử dụng Write2d () chức năng.

gấp đôi thời gian;
giá trị nhân đôi;

// Tạo tập dữ liệu 2-D.
cho (thời gian = -5.0; thời gian <= +5.0; thời gian + = 1.0)
{
// Tính đường cong 2-D
//
// 2
// giá trị = thời gian.
//
giá trị = thời gian * thời gian;

// Thêm điểm này vào cốt truyện.
bộ tổng hợp-> Write2d (datasetContext, thời gian, giá trị);
}

// Tắt ghi dữ liệu cho trình tổng hợp.
bộ tổng hợp-> Disable ();
}

Trình tổng hợp tệp
FileAggregator gửi các giá trị mà nó nhận được vào một tệp.

FileAggregator có thể tạo 4 loại tệp khác nhau:

· Đã định dạng

· Không gian tách biệt (mặc định)

· Phân tách bằng dấu phẩy

· Tab được phân tách

Các tệp được định dạng sử dụng chuỗi định dạng kiểu C và hàm sprintf () để in
giá trị trong tệp đang được ghi.

Sáng tạo
Một đối tượng kiểu FileAggregator sẽ được tạo ở đây để hiển thị những gì cần phải làm.

Người ta khai báo một FileAggregator trong bộ nhớ động bằng cách sử dụng lớp con trỏ thông minh (Ptr ).
Để tạo FileAggregator trong bộ nhớ động với con trỏ thông minh, người ta chỉ cần gọi
các ns-3 phương thức CreateObject. Đoạn mã sau từ
src / stats /amples / file-aggregator-example.cc chỉ cách làm điều này:

string fileName = "tệp-tổng hợp-định dạng-giá trị.txt";

// Tạo một trình tổng hợp sẽ có các giá trị được định dạng.
Ptr người tổng hợp =
CreateObject (fileName, FileAggregator :: FORMATTED);

Đối số đầu tiên cho hàm tạo, tên tệp, là tên của tệp để ghi; các
đối số thứ hai, fileType, là loại tệp để ghi. FileAggregator này sẽ tạo ra một
tệp có tên "tệp-tổng hợp-định dạng-giá trị.txt" với các giá trị của nó được in như được chỉ định bởi
fileType, tức là, được định dạng trong trường hợp này.

Các giá trị enum loại tệp sau được cho phép:

enum Loại tệp {
ĐÃ ĐỊNH DẠNG,
SPACE_SEPARATED,
COMMA_SEPARATED,
TAB_SEPARATED
};

Các ví dụ
Một ví dụ sẽ được thảo luận chi tiết ở đây:

· Ví dụ về công cụ tổng hợp tệp

Tập tin Bộ tổng hợp Ví dụ
Có thể tìm thấy một ví dụ thực hành FileAggregator trong
src / stats /amples / file-aggregator-example.cc.

Tệp văn bản sau với 2 cột giá trị được phân tách bằng dấu phẩy đã được tạo bằng cách sử dụng
thí dụ.

-5,25
-4,16
-3,9
-2,4
-1,1
0,0
1,1
2,4
3,9
4,16
5,25

Đoạn mã từ ví dụ này cho thấy cách tạo FileAggregator như đã được thảo luận
ở trên.

void CreateCommaSeparatedFile()
{
sử dụng namespace std;

string fileName = "tập tin-tổng hợp-dấu phẩy-phân tách.txt";
string datasetContext = "Dataset / Context / String";

// Tạo một trình tổng hợp.
Ptr người tổng hợp =
CreateObject (fileName, FileAggregator :: COMMA_SEPARATED);

Thuộc tính FileAggregator được thiết lập.

// bộ tổng hợp phải được bật
bộ tổng hợp-> Enable ();

Tiếp theo, các giá trị 2-D được tính toán và mỗi giá trị được ghi riêng vào
FileAggregator bằng cách sử dụng Write2d () chức năng.

gấp đôi thời gian;
giá trị nhân đôi;

// Tạo tập dữ liệu 2-D.
cho (thời gian = -5.0; thời gian <= +5.0; thời gian + = 1.0)
{
// Tính đường cong 2-D
//
// 2
// giá trị = thời gian.
//
giá trị = thời gian * thời gian;

// Thêm điểm này vào cốt truyện.
bộ tổng hợp-> Write2d (datasetContext, thời gian, giá trị);
}

// Tắt ghi dữ liệu cho trình tổng hợp.
bộ tổng hợp-> Disable ();
}

Tệp văn bản sau với 2 cột giá trị được định dạng cũng được tạo bằng cách sử dụng
thí dụ.

Thời gian = -5.000e + 00 Giá trị = 25
Thời gian = -4.000e + 00 Giá trị = 16
Thời gian = -3.000e + 00 Giá trị = 9
Thời gian = -2.000e + 00 Giá trị = 4
Thời gian = -1.000e + 00 Giá trị = 1
Thời gian = 0.000e + 00 Giá trị = 0
Thời gian = 1.000e + 00 Giá trị = 1
Thời gian = 2.000e + 00 Giá trị = 4
Thời gian = 3.000e + 00 Giá trị = 9
Thời gian = 4.000e + 00 Giá trị = 16
Thời gian = 5.000e + 00 Giá trị = 25

Đoạn mã từ ví dụ này cho thấy cách tạo FileAggregator như đã được thảo luận
ở trên.

void CreateFormattedFile()
{
sử dụng namespace std;

string fileName = "tệp-tổng hợp-định dạng-giá trị.txt";
string datasetContext = "Dataset / Context / String";

// Tạo một trình tổng hợp sẽ có các giá trị được định dạng.
Ptr người tổng hợp =
CreateObject (fileName, FileAggregator :: FORMATTED);

Thuộc tính FileAggregator được đặt, bao gồm cả chuỗi định dạng C-style để sử dụng.

// Đặt định dạng cho các giá trị.
tổng hợp-> Set2dFormat ("Thời gian =% .3e \ tValue =% .0f");

// bộ tổng hợp phải được bật
bộ tổng hợp-> Enable ();

Tiếp theo, các giá trị 2-D được tính toán và mỗi giá trị được ghi riêng vào
FileAggregator bằng cách sử dụng Write2d () chức năng.

gấp đôi thời gian;
giá trị nhân đôi;

// Tạo tập dữ liệu 2-D.
cho (thời gian = -5.0; thời gian <= +5.0; thời gian + = 1.0)
{
// Tính đường cong 2-D
//
// 2
// giá trị = thời gian.
//
giá trị = thời gian * thời gian;

// Thêm điểm này vào cốt truyện.
bộ tổng hợp-> Write2d (datasetContext, thời gian, giá trị);
}

// Tắt ghi dữ liệu cho trình tổng hợp.
bộ tổng hợp-> Disable ();
}

Bộ điều hợp
Phần này trình bày chi tiết các chức năng được cung cấp bởi lớp Bộ điều hợp cho một ns-3
mô phỏng. Phần này dành cho những người dùng quan tâm đến việc phát triển mô phỏng với
ns-3 và sử dụng Khung thu thập dữ liệu, trong đó lớp Bộ điều hợp là một phần,
để tạo đầu ra dữ liệu với kết quả mô phỏng của họ.

Lưu ý: thuật ngữ 'bộ điều hợp' cũng có thể được đánh vần là 'bộ điều hợp'; chúng tôi đã chọn căn chỉnh chính tả
với tiêu chuẩn C ++.

Adaptor Giới thiệu chung
Bộ điều hợp được sử dụng để tạo kết nối giữa các loại đối tượng DCF khác nhau.

Đến nay, một Bộ điều hợp đã được triển khai:

· Bộ điều hợp dòng thời gian

Thời gian Loạt Sách Adaptor
TimeSeriesAdaptor cho phép Probe kết nối trực tiếp với Aggregators mà không cần bất kỳ
Bộ sưu tập ở giữa.

Cả hai trình trợ giúp DCF được triển khai đều sử dụng TimeSeriesAdaptors để thực hiện
giá trị của các loại khác nhau và xuất ra thời gian hiện tại cộng với giá trị với cả hai loại được chuyển đổi
tăng gấp đôi.

Vai trò của lớp TimeSeriesAdaptor là một bộ điều hợp, có giá trị thô
thăm dò dữ liệu của các loại khác nhau và xuất ra một bộ hai giá trị kép. Đầu tiên là một
dấu thời gian, có thể được đặt thành các độ phân giải khác nhau (ví dụ: Giây, Mili giây, v.v.) trong
tương lai nhưng hiện được mã hóa cứng thành Giây. Thứ hai là việc chuyển đổi một
giá trị không kép thành giá trị kép (có thể mất độ chính xác).

Phạm vi / Hạn chế
Phần này thảo luận về phạm vi và giới hạn của Khung thu thập dữ liệu.

Hiện tại, chỉ những Đầu dò này đã được triển khai trong DCF:

· Đầu dò Boolean

· Đầu dò đôi

· Uinteger8Probe

· Uinteger16Probe

· Uinteger32Probe

· Thời gian thăm dò

· Đầu dò gói

· Ứng dụngPacketProbe

· Ipv4PacketProbe

Hiện tại, không có Bộ sưu tập nào có sẵn trong DCF, mặc dù Bộ sưu tập BasicStats
phát triển.

Hiện tại, chỉ những Trang tổng hợp này được triển khai trong DCF:

· Công cụ tổng hợp Gnuplot

· Trình tổng hợp tệp

Hiện tại, chỉ có Bộ điều hợp này được triển khai trong DCF:

Bộ điều hợp dòng thời gian.

Tương lai Công việc
Phần này thảo luận về công việc trong tương lai sẽ được thực hiện trên Khung thu thập dữ liệu.

Dưới đây là một số điều vẫn cần được thực hiện:

· Kết nối nhiều nguồn theo dõi hơn trong ns-3 mã để nhận được nhiều giá trị hơn từ trình mô phỏng.

· Triển khai nhiều loại Đầu dò hơn hiện tại.

· Triển khai nhiều hơn chỉ là Bộ sưu tập 2-D hiện tại, BasicStatsCollector.

· Triển khai nhiều Aggregators hơn.

· Thực hiện nhiều hơn chỉ Bộ điều hợp.

Thống kê Khung
Chương này phác thảo công việc thu thập dữ liệu mô phỏng và khung thống kê cho
ns-3.

Mã nguồn của khung thống kê nằm trong thư mục src / stats.

Các mục tiêu
Mục tiêu chính cho nỗ lực này là như sau:

· Cung cấp chức năng ghi lại, tính toán và trình bày dữ liệu, số liệu thống kê để phân tích
của các mô phỏng mạng.

· Tăng cường hiệu suất mô phỏng bằng cách giảm nhu cầu tạo nhật ký theo dõi mở rộng trong
để thu thập dữ liệu.

· Cho phép điều khiển mô phỏng thông qua thống kê trực tuyến, ví dụ như kết thúc mô phỏng hoặc
thử nghiệm lặp đi lặp lại.

Các mục tiêu phụ bắt nguồn và các tính năng mục tiêu khác bao gồm:

· Tích hợp với hệ thống theo dõi ns-3 hiện có làm khung thiết bị cơ bản
của công cụ mô phỏng nội bộ, ví dụ như ngăn xếp mạng, thiết bị mạng và kênh.

· Cho phép người dùng sử dụng khung thống kê mà không yêu cầu sử dụng tính năng theo dõi
hệ thống.

· Giúp người dùng tạo, tổng hợp và phân tích dữ liệu qua nhiều lần thử nghiệm.

· Hỗ trợ cho các thiết bị do người dùng tạo, ví dụ như các sự kiện cụ thể của ứng dụng và
biện pháp.

· Chi phí bộ nhớ và CPU thấp khi gói không được sử dụng.

· Tận dụng tối đa các công cụ phân tích và đầu ra hiện có. Khuôn khổ có thể
cung cấp một số số liệu thống kê cơ bản nhưng trọng tâm là thu thập dữ liệu và làm cho nó
có thể truy cập để thao tác trong các công cụ đã được thiết lập.

· Hỗ trợ cuối cùng cho việc phân phối các bản sao độc lập là quan trọng nhưng không được bao gồm
trong vòng tính năng đầu tiên.

Giới thiệu chung
Khung thống kê bao gồm các tính năng sau:

· Khung cốt lõi và hai bộ thu thập dữ liệu cơ bản: Bộ đếm và bộ đếm tối thiểu/tối đa/trung bình/tổng
người quan sát.

· Phần mở rộng của chúng để dễ dàng làm việc với thời gian và gói.

· Bản rõ đầu ra được định dạng cho OMNet ++.

· Xuất cơ sở dữ liệu bằng cách sử dụng SQLite, một công cụ SQL độc lập, nhẹ, hiệu suất cao.

· Siêu dữ liệu bắt buộc và mở để mô tả và làm việc với các lần chạy.

· Ví dụ dựa trên thí nghiệm lý thuyết kiểm tra tính chất của NS-3
hiệu suất WiFi đặc biệt mặc định. Nó kết hợp những điều sau đây:

· Xây dựng mạng WiFi đặc biệt hai nút, với các nút có khoảng cách được tham số hóa
ngoài.

· Các ứng dụng nguồn và đích lưu lượng UDP có hành vi hơi khác một chút và
móc đo hơn so với các lớp chứng khoán.

· Thu thập dữ liệu từ lõi NS-3 thông qua các tín hiệu dấu vết hiện có, đặc biệt là dữ liệu về
các khung được truyền và nhận bởi các đối tượng MAC WiFi.

· Thiết bị đo các ứng dụng tùy chỉnh bằng cách kết nối các tín hiệu theo dõi mới với chỉ số
framework, cũng như thông qua cập nhật trực tiếp. Thông tin được ghi lại về tổng số gói
gửi và nhận, byte được truyền và độ trễ từ đầu đến cuối.

· Một ví dụ về việc sử dụng thẻ gói để theo dõi độ trễ từ đầu đến cuối.

· Một tập lệnh điều khiển đơn giản chạy một số thử nghiệm ở các mức độ khác nhau
khoảng cách và truy vấn cơ sở dữ liệu kết quả để tạo biểu đồ bằng GNUPlot.

Làm
Các mục có mức độ ưu tiên cao bao gồm:

· Bao gồm mã thống kê trực tuyến, ví dụ như khoảng tin cậy hiệu quả của bộ nhớ.

· Các quy định trong bộ thu thập dữ liệu về việc chấm dứt các lần chạy, tức là khi đạt đến ngưỡng hoặc
sự tự tin được đáp ứng.

· Trình thu thập dữ liệu để ghi lại các mẫu theo thời gian và xuất ra các định dạng khác nhau.

· Chứng minh cách viết keo sự kiện tuần hoàn đơn giản để thường xuyên thăm dò một số giá trị.

Mỗi trong số đó phải được chứng minh là dễ dàng kết hợp trong khuôn khổ hiện tại.

Phương pháp tiếp cận
Khung này dựa trên các nguyên tắc cốt lõi sau:

· Một thử nghiệm được thực hiện bằng một phiên bản của chương trình mô phỏng, dù ở
song song hoặc nối tiếp.

· Một tập lệnh điều khiển thực thi các phiên bản mô phỏng, thay đổi các tham số nếu cần.

· Dữ liệu được thu thập và lưu trữ để vẽ và phân tích bằng cách sử dụng các tập lệnh bên ngoài và
các công cụ hiện có.

· Các biện pháp trong lõi ns-3 được thực hiện bằng cách kết nối khung thống kê với khung hiện có
dấu vết tín hiệu.

· Tín hiệu theo dõi hoặc thao tác trực tiếp của khung có thể được sử dụng để tùy chỉnh công cụ
mã mô phỏng.

Những thành phần cơ bản của khung và sự tương tác của chúng được mô tả trong
hình sau. [hình ảnh]

Ví dụ
Phần này trình bày quá trình xây dựng một thí nghiệm trong khuôn khổ và
tạo ra dữ liệu để phân tích (biểu đồ) từ đó, thể hiện cấu trúc và API cùng với
cách.

câu hỏi
''Hiệu suất (mô phỏng) của WiFi NetDevices của ns-3 là gì (sử dụng mặc định
cài đặt)? Các nút không dây có thể cách nhau bao xa trong mô phỏng trước khi chúng không thể
giao tiếp đáng tin cậy?''

· Giả thuyết: Dựa trên kiến ​​thức về hiệu suất thực tế, các nút nên giao tiếp
khá tốt cách nhau ít nhất 100m. Không nên liên lạc ngoài 200m
khả thi.

Mặc dù đây không phải là một câu hỏi phổ biến trong bối cảnh mô phỏng, nhưng đây là một đặc tính quan trọng
trong đó các nhà phát triển mô phỏng nên có hiểu biết cơ bản. Đó cũng là điều phổ biến
nghiên cứu được thực hiện trên phần cứng trực tiếp.

Mô phỏng chương trình
Điều đầu tiên cần làm khi thực hiện thí nghiệm này là phát triển mô phỏng
chương trình. Mã cho ví dụ này có thể được tìm thấy trong ví dụ/số liệu thống kê/wifi-example-sim.cc.
Nó thực hiện các bước chính sau đây.

· Khai báo tham số và phân tích dòng lệnh bằng ns3::Dòng lệnh.

khoảng cách gấp đôi = 50.0;
định dạng chuỗi ("OMNet++");
thử nghiệm chuỗi ("kiểm tra khoảng cách wifi");
chiến lược chuỗi ("mặc định wifi");
chuỗi runID;

Dòng lệnh cmd;
cmd.AddValue("khoảng cách", "Khoảng cách để đặt các nút (tính bằng mét).", khoảng cách);
cmd.AddValue("format", "Định dạng dùng cho dữ liệu đầu ra.", format);
cmd.AddValue("thử nghiệm", "Mã định danh cho thử nghiệm.", thử nghiệm);
cmd.AddValue("chiến lược", "Mã định danh cho chiến lược.", chiến lược);
cmd.AddValue("run", "Mã định danh cho lần chạy.", runID);
cmd.Parse(argc, argv);

· Tạo các nút và ngăn xếp mạng bằng cách sử dụng ns3 :: NodeContainer, ns3::Trình trợ giúp WiFi
ns3 :: InternetStackHelper.

Các nút NodeContainer;
nút.Tạo(2);

WifiHelper wifi;
wifi.SetMac("ns3::AdhocWifiMac");
wifi.SetPhy("ns3::WifiPhy");
Nút NetDeviceContainerDevices = wifi.Install(node);

Internet InternetStackHelper;
internet.Install (nút);
Ipv4AddressHelper ipAddrs;
ipAddrs.SetBase("192.168.0.0", "255.255.255.0");
ipAddrs.Assign(nodeDevices);

· Định vị các nút bằng cách sử dụng ns3::Trình trợ giúp di động. Theo mặc định, các nút có trạng thái tĩnh
khả năng di chuyển và sẽ không di chuyển, nhưng phải được đặt cách nhau một khoảng nhất định. Có
một số cách để làm điều này; nó được thực hiện ở đây bằng cách sử dụng ns3::ListPositionAllocator, vẽ
các vị trí từ một danh sách nhất định.

Khả năng di chuyển tốt hơn;
Ptr vị tríAlloc =
Tạo đối tượng ();
vị tríAlloc->Thêm (Vector (0.0, 0.0, 0.0));
vị tríAlloc->Thêm (Vector (0.0, khoảng cách, 0.0));
tính di động.SetPositionAllocator(positionAlloc);
tính di động.Install (nút);

· Lắp đặt bộ tạo lưu lượng và giảm lưu lượng. Chứng khoán Ứng dụng có thể
được sử dụng, nhưng ví dụ này bao gồm các đối tượng tùy chỉnh trong src/test/test02-apps.(cc|h). Kia là
có một hành vi đơn giản, tạo ra một số lượng gói nhất định cách nhau trong một khoảng thời gian nhất định.
Vì chỉ có một cái nên chúng được cài đặt thủ công; đối với một bộ lớn hơn
ns3::Trình trợ giúp ứng dụng lớp có thể được sử dụng Đã nhận xét Cấu hình :: Đặt thay đổi dòng
đích của các gói, được đặt thành phát theo mặc định trong ví dụ này. Lưu ý rằng
nói chung WiFi có thể có hiệu suất khác nhau đối với các khung phát sóng và khung đơn hướng do
các chính sách kiểm soát tốc độ và truyền lại MAC khác nhau.

Ptr appSource = Danh sách nút::GetNode(0);
Ptr người gửi = CreateObject ();
appSource->AddApplication(người gửi);
người gửi->Bắt đầu(Giây(1));

Ptr appSink = Danh sách nút::GetNode(1);
Ptr người nhận = CreateObject ();
appSink->AddApplication(bộ thu);
người nhận->Bắt đầu(Giây(0));

// Config::Set("/NodeList/*/ApplicationList/*/$Sender/Destination",
// Ipv4AddressValue("192.168.0.2"));

· Cấu hình dữ liệu và số liệu thống kê cần thu thập. Mô hình cơ bản là một
ns3::Bộ thu thập dữ liệu đối tượng được tạo để chứa thông tin về lần chạy cụ thể này, để
những người quan sát và máy tính được gắn vào để thực sự tạo ra dữ liệu. Điều quan trọng là,
thông tin chạy bao gồm các nhãn cho ''thử nghiệm'', ''chiến lược'', ''đầu vào'' và
''chạy''. Chúng được sử dụng để sau này xác định và dễ dàng nhóm dữ liệu từ nhiều thử nghiệm.

· Thí nghiệm là nghiên cứu mà thử nghiệm này là thành viên. Đây là trên WiFi
hiệu suất và khoảng cách.

· Chiến lược là mã hoặc các tham số đang được kiểm tra trong thử nghiệm này. Trong ví dụ này
nó đã được sửa, nhưng một phần mở rộng rõ ràng là điều tra bit WiFi khác nhau
tỷ giá, mỗi tỷ giá sẽ là một chiến lược khác nhau.

· Đầu vào là bài toán cụ thể được đưa ra cho lần thử nghiệm này. Ở đây đơn giản nó là
khoảng cách giữa hai nút.

· RunID là mã định danh duy nhất cho bản dùng thử này với thông tin được gắn thẻ
để xác định trong phân tích sau này. Nếu không có ID lần chạy nào được cung cấp, chương trình ví dụ sẽ thực hiện
ID chạy (yếu) sử dụng thời gian hiện tại.

Bốn phần siêu dữ liệu đó là bắt buộc nhưng có thể cần nhiều hơn. Chúng có thể được thêm vào
vào bản ghi bằng cách sử dụng ns3::DataCollector::AddMetadata() phương pháp.

Dữ liệu DataCollector;
data.DescribeRun(thử nghiệm, chiến lược, đầu vào, runID);
data.AddMetadata("tác giả", "tjkopena");

Việc quan sát và tính toán thực tế được thực hiện bằng ns3::Máy tính dữ liệu đồ vật, trong đó
tồn tại một số loại khác nhau. Chúng được tạo ra bởi chương trình mô phỏng, gắn liền với
mã báo cáo hoặc lấy mẫu, sau đó đăng ký với ns3::Bộ thu thập dữ liệu vì vậy họ sẽ
được truy vấn sau này về đầu ra của chúng. Một cơ chế quan sát dễ dàng là sử dụng
theo dõi các nguồn, ví dụ như để điều khiển các đối tượng trong lõi ns-3 mà không thay đổi chúng
mã số. Ở đây, bộ đếm được gắn trực tiếp vào tín hiệu theo dõi trong lớp MAC WiFi trên
nút đích.

Ptr tổngRx = CreateObject ();
TotalRx->SetKey("wifi-rx-frames");
Config::Connect("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Rx",
MakeCallback(&PacketCounterCalculator::FrameUpdate, TotalRx));
data.AddDataCalculator(totalRx);

Máy tính cũng có thể được thao tác trực tiếp. Trong ví dụ này, một bộ đếm được tạo ra và
được chuyển đến ứng dụng thu thập lưu lượng để được cập nhật khi nhận được gói.

Ptr > appRx = CreateObject >();
appRx->SetKey("receiver-rx-packets");
người nhận->SetCounter(appRx);
data.AddDataCalculator(appRx);

Để tăng số lượng, mã xử lý gói của sink sẽ gọi một trong các
phương pháp cập nhật của máy tính.

m_calc->Cập nhật();

Chương trình này cũng bao gồm một số ví dụ khác, sử dụng cả kiểu nguyên thủy
máy tính như ns3::Máy tính bộ đếm và những thứ thích hợp để quan sát các gói và
lần. TRONG src/test/test02-apps.(cc|h) nó cũng tạo ra một thẻ tùy chỉnh đơn giản mà nó sử dụng
để theo dõi độ trễ từ đầu đến cuối cho các gói được tạo, báo cáo kết quả cho
ns3::TimeMinMaxAvgTotalCalculator máy tính dữ liệu.

· Chạy mô phỏng, việc này rất đơn giản sau khi được xây dựng.

Trình mô phỏng::Chạy();

· Tạo một trong hai OMNet ++ or SQLite đầu ra, tùy thuộc vào các đối số dòng lệnh. ĐẾN
làm điều này một ns3::DataOutputInterface đối tượng được tạo và cấu hình. Loại cụ thể
điều này sẽ xác định định dạng đầu ra. Đối tượng này sau đó được cấp
ns3::Bộ thu thập dữ liệu đối tượng mà nó thẩm vấn để tạo ra đầu ra.

Ptr đầu ra;
if (định dạng == "OMNet++") {
NS_LOG_INFO("Tạo đầu ra dữ liệu có định dạng OMNet++.");
đầu ra = CreateObject ();
} Else {
# ifdef STAT_USE_DB
NS_LOG_INFO("Tạo đầu ra dữ liệu có định dạng SQLite.");
đầu ra = CreateObject ();
# kết thúc
}

đầu ra->Đầu ra(dữ liệu);

· Giải phóng mọi bộ nhớ được sử dụng bởi mô phỏng. Điều này sẽ đến ở cuối phần chính
chức năng cho ví dụ.

Trình mô phỏng::Tiêu diệt();

Logging
Để xem chi tiết chương trình ví dụ, ứng dụng và khung thống kê đang làm gì, hãy đặt
các NS_LOG biến một cách thích hợp. Sau đây sẽ cung cấp đầu ra phong phú từ tất cả
số ba.

$ xuất NS_LOG=Thử nghiệm WiFiDistance:WiFiDistanceApps

Lưu ý rằng điều này làm chậm quá trình mô phỏng một cách bất thường.

Mâu Đầu ra
Biên dịch và chỉ cần chạy chương trình thử nghiệm sẽ nối thêm OMNet ++ đầu ra được định dạng như
những điều sau đây để dữ liệu.sca.

chạy run-1212239121

thử nghiệm attr "kiểm tra khoảng cách wifi"
chiến lược attr "mặc định wifi"
đầu vào attr "50"
mô tả attr ""

attr "tác giả" "tjkopena"

số khung wifi-tx vô hướng đếm 30
số khung wifi-rx vô hướng đếm 30
số lượng gói gửi-tx vô hướng là 30
số gói nhận-rx vô hướng đếm 30
số lượng kích thước tx-pkt vô hướng 30
tổng kích thước tx-pkt vô hướng 1920
vô hướng tx-pkt-kích thước trung bình 64
vô hướng tx-pkt-size tối đa 64
vô hướng tx-pkt-size tối thiểu 64
số lượng độ trễ vô hướng 30
tổng độ trễ vô hướng 5884980ns
độ trễ vô hướng trung bình 196166ns
độ trễ vô hướng tối đa 196166ns
độ trễ vô hướng tối thiểu 196166ns

Kiểm soát Script
Để tự động hóa việc thu thập dữ liệu ở nhiều đầu vào (khoảng cách) khác nhau, một Bash đơn giản
script được sử dụng để thực hiện một loạt các mô phỏng. Nó có thể được tìm thấy tại
ví dụ/thống kê/wifi-example-db.sh. Kịch bản có nghĩa là được chạy từ ví dụ/số liệu thống kê/
thư mục.

Kịch bản chạy qua một tập hợp các khoảng cách, thu thập kết quả vào một SQLite
cơ sở dữ liệu. Ở mỗi khoảng cách, năm thử nghiệm được tiến hành để đưa ra bức tranh rõ hơn về dự kiến
hiệu suất. Toàn bộ thử nghiệm chỉ mất vài chục giây để chạy ở mức thấp
máy vì không có đầu ra trong quá trình mô phỏng và có ít lưu lượng được tạo ra.

#!/ Bin / sh

KHOẢNG CÁCH="25 50 75 100 125 145 147 150 152 155 157 160 162 165 167 170 172 175 177 180"
THỬ NGHIỆM="1 2 3 4 5"

echo Ví dụ về thử nghiệm WiFi

nếu [ -e data.db ]
sau đó
echo Giết data.db?
đọc câu trả lời
nếu [ "$ANS" = "có" -o "$ANS" = "y" ]
sau đó
echo Đang xóa cơ sở dữ liệu
dữ liệu rm.db
fi
fi

để dùng thử trong $TRIALS
do
cho khoảng cách tính bằng $DISTANCES
do
echo Bản dùng thử $thử nghiệm, khoảng cách $khoảng cách
./bin/test02 --format=db --distance=$distance --run=run-$distance-$trial
thực hiện
thực hiện

nghiên cứu Kết luận
Khi tất cả các thử nghiệm đã được tiến hành, tập lệnh sẽ thực thi một truy vấn SQL đơn giản trên
cơ sở dữ liệu bằng cách sử dụng SQLite chương trình dòng lệnh. Truy vấn tính toán mức độ mất gói trung bình trong
mỗi bộ thử nghiệm liên quan đến từng khoảng cách. Nó không tính đến sự khác biệt
chiến lược, nhưng thông tin có sẵn trong cơ sở dữ liệu để thực hiện một số phần mở rộng đơn giản
và làm như vậy. Dữ liệu được thu thập sau đó được chuyển đến GNUPlot để vẽ đồ thị.

CMD="select exp.input,avg(100-((rx.value*100)/tx.value)) \
từ Singletons rx, Singletons tx, Thí nghiệm exp \
trong đó rx.run = tx.run VÀ \
rx.run = exp.run VÀ \
rx.name='receiver-rx-packets' VÀ \
tx.name='sender-tx-packets' \
nhóm theo exp.input \
sắp xếp theo abs(exp.input) ASC;"

sqlite3 -noheader data.db "$CMD" > wifi-default.data
sed -i "s/|/ /" wifi-default.data
gnuplot wifi-example.gnuplot

Tập lệnh GNUPlot được tìm thấy tại ví dụ/số liệu thống kê/wifi-example.gnuplot chỉ cần xác định đầu ra
định dạng và một số định dạng cơ bản cho biểu đồ.

đặt chân dung phần mô tả của thiết bị đầu cuối được nâng cao lw 2 "Helvetica" 14

đặt kích thước 1.0, 0.66

#------------------------------------------------ ------
đặt ra "wifi-default.eps"
#set tiêu đề "Mất gói theo khoảng cách"
đặt xlabel "Khoảng cách (m) --- trung bình 5 lần thử mỗi điểm"
đặt xrange [0:200]
đặt nhãn "% mất gói"
đặt yrange [0:110]

vẽ sơ đồ "wifi-default.data" với dòng tiêu đề "Mặc định WiFi"

Kết bài Kết quả
Biểu đồ kết quả không cung cấp bằng chứng nào cho thấy hiệu suất của mô hình WiFi mặc định là
nhất thiết là không hợp lý và tạo ra sự tự tin ít nhất là về sự trung thành đối với
thực tế. Quan trọng hơn, cuộc điều tra đơn giản này đã được thực hiện xuyên suốt
sử dụng khung thống kê. Thành công! [hình ảnh]

Thời gian thực
ns-3 đã được thiết kế để tích hợp vào môi trường thử nghiệm và máy ảo. ĐẾN
tích hợp với các ngăn xếp mạng thực và phát/tiêu thụ các gói, bộ lập lịch thời gian thực là
cần cố gắng khóa đồng hồ mô phỏng bằng đồng hồ phần cứng. Chúng tôi mô tả ở đây một
thành phần của điều này: bộ lập lịch thời gian thực.

Mục đích của bộ lập lịch thời gian thực là tạo ra sự tiến triển của đồng hồ mô phỏng
xảy ra đồng bộ theo một số cơ sở thời gian bên ngoài. Nếu không có sự hiện diện của
cơ sở thời gian bên ngoài (đồng hồ treo tường), thời gian mô phỏng sẽ nhảy ngay lập tức từ một thời gian mô phỏng
thời gian tiếp theo.

Hành vi
Khi sử dụng bộ lập lịch không theo thời gian thực (mặc định trong ns-3), trình mô phỏng tiến bộ
thời gian mô phỏng đến sự kiện được lên lịch tiếp theo. Trong quá trình thực hiện sự kiện, thời gian mô phỏng là
Đông cứng. Với bộ lập lịch thời gian thực, hành vi tương tự từ góc độ của
mô phỏng (tức là thời gian mô phỏng bị cố định trong quá trình thực hiện sự kiện), nhưng giữa
sự kiện, trình mô phỏng sẽ cố gắng giữ đồng hồ mô phỏng thẳng hàng với máy
đồng hồ.

Khi một sự kiện được thực hiện xong và bộ lập lịch chuyển sang sự kiện tiếp theo,
bộ lập lịch so sánh thời gian thực hiện sự kiện tiếp theo với đồng hồ máy. Nếu tiếp theo
sự kiện được lên lịch cho một thời điểm trong tương lai, trình mô phỏng sẽ ngủ cho đến khi đạt đến thời gian thực đó
rồi thực hiện sự kiện tiếp theo.

Có thể xảy ra rằng, do quá trình xử lý vốn có trong việc thực hiện các sự kiện mô phỏng,
rằng trình mô phỏng không thể theo kịp thời gian thực. Trong trường hợp như vậy, tùy người dùng
cấu hình phải làm gì Có hai ns-3 thuộc tính chi phối hành vi. Các
Đầu tiên là ns3::RealTimeSimulatorImpl::Chế độ đồng bộ hóa. Hai mục có thể cho
thuộc tính này là Nỗ lực tốt nhất (mặc định) hoặc giới hạn cứng. Trong chế độ "BestEffort",
trình mô phỏng sẽ chỉ cố gắng bắt kịp thời gian thực bằng cách thực hiện các sự kiện cho đến khi đạt đến mức
điểm mà sự kiện tiếp theo diễn ra trong tương lai (thời gian thực), nếu không quá trình mô phỏng sẽ kết thúc. TRONG
Khi đó, chế độ BestEffort có thể khiến mô phỏng tiêu tốn nhiều thời gian hơn chế độ
đồng hồ treo tường thời gian. Tùy chọn khác "HardLimit" sẽ khiến mô phỏng bị hủy bỏ nếu
ngưỡng chịu đựng bị vượt quá. Thuộc tính này là ns3::RealTimeSimulatorImpl::HardLimit
và mặc định là 0.1 giây.

Một chế độ hoạt động khác là chế độ trong đó thời gian mô phỏng được không bị đóng băng trong một sự kiện
chấp hành. Chế độ mô phỏng thời gian thực này đã được triển khai nhưng đã bị loại bỏ khỏi ns-3 cây
vì câu hỏi liệu nó có hữu ích hay không. Nếu người dùng quan tâm đến thời gian thực
trình mô phỏng mà thời gian mô phỏng không bị đóng băng trong quá trình thực hiện sự kiện (nghĩa là mọi
gọi tới Trình mô phỏng::Bây giờ() trả về thời gian hiện tại của đồng hồ treo tường, không phải thời gian mà
sự kiện bắt đầu thực thi), vui lòng liên hệ với danh sách gửi thư của ns-developers.

Sử dụng
Việc sử dụng trình mô phỏng thời gian thực rất đơn giản, từ góc độ kịch bản.
Người dùng chỉ cần thiết lập thuộc tính Trình mô phỏngLoại thực hiện đến thời gian thực
mô phỏng, chẳng hạn như sau:

GlobalValue::Bind ("SimulatorImplementationType",
StringValue ("ns3::RealtimeSimulatorImpl"));

Có một kịch bản trong ví dụ/thời gian thực/thời gian thực-udp-echo.cc có một ví dụ về cách
cấu hình hành vi thời gian thực. Thử:

$ ./waf --run realtime-udp-echo

Liệu trình mô phỏng sẽ hoạt động với nỗ lực tốt nhất hay chính sách giới hạn cứng sẽ được điều chỉnh
bởi các thuộc tính được giải thích ở phần trước.

Triển khai hệ thống
Việc triển khai được chứa trong các tệp sau:

· src/core/model/realtime-simulator-impl.{cc,h}

· src/core/model/wall-clock-synchronizer.{cc,h}

Để tạo một bộ lập lịch thời gian thực, với giá trị gần đúng đầu tiên bạn chỉ muốn tạo ra
thời gian mô phỏng nhảy để tiêu thụ thời gian thực. Chúng tôi đề xuất thực hiện việc này bằng cách sử dụng kết hợp
ngủ - và bận - chờ đợi. Chờ đợi khiến quá trình gọi (luồng) mang lại kết quả
bộ xử lý trong một khoảng thời gian. Mặc dù khoảng thời gian quy định này có thể được thông qua
thành độ phân giải nano giây, nó thực sự được chuyển đổi thành độ chi tiết dành riêng cho hệ điều hành. TRONG
Linux, mức độ chi tiết được gọi là Jiffy. Thông thường độ phân giải này không đủ để
nhu cầu của chúng ta (theo thứ tự mười mili giây), vì vậy chúng ta làm tròn xuống và ngủ một lát
số lượng Jiffies nhỏ hơn. Quá trình này sau đó được đánh thức sau số lần xác định
Jiffies đã qua. Tại thời điểm này, chúng tôi có một số thời gian còn lại để chờ đợi. Lần này là
thường nhỏ hơn thời gian ngủ tối thiểu, vì vậy chúng ta bận rộn chờ đợi phần còn lại của
thời gian. Điều này có nghĩa là luồng chỉ nằm trong một vòng lặp for cho đến khi
thời gian mong muốn đã đến. Sau khi kết hợp giữa chế độ ngủ và chờ bận, thời gian thực đã trôi qua
Đồng hồ (tường) phải phù hợp với thời gian mô phỏng của sự kiện tiếp theo và mô phỏng
tiền thu được.

Người giúp việc
Các chương trên đã giới thiệu cho bạn nhiều ns-3 các khái niệm lập trình như thông minh
con trỏ để quản lý bộ nhớ được tính tham chiếu, thuộc tính, không gian tên, lệnh gọi lại, v.v.
Người dùng làm việc ở API cấp thấp này có thể kết nối với nhau ns-3 vật thể có dạng hạt mịn.
Tuy nhiên, một chương trình mô phỏng được viết hoàn toàn bằng API cấp thấp sẽ khá dài.
và tẻ nhạt khi viết mã. Vì lý do này, cái gọi là "API trợ giúp" riêng biệt đã được phủ lên
trên cốt lõi ns-3 API. Nếu bạn đã đọc ns-3 hướng dẫn, bạn sẽ quen thuộc
với API trợ giúp, vì đây là API mà người dùng mới thường được giới thiệu đầu tiên.
Trong chương này, chúng tôi giới thiệu triết lý thiết kế của API trợ giúp và đối chiếu nó với
API cấp thấp. Nếu bạn trở thành người sử dụng nhiều ns-3, bạn có thể sẽ di chuyển qua lại
giữa các API này ngay cả trong cùng một chương trình.

API trợ giúp có một số mục tiêu:

1. phần còn lại của src / không phụ thuộc vào API trợ giúp; bất cứ điều gì có thể được thực hiện với
API trợ giúp cũng có thể được mã hóa ở API cấp thấp

2. Hộp đựng: Thông thường các mô phỏng sẽ cần thực hiện một số hành động giống nhau cho các nhóm
của các đồ vật. API trợ giúp sử dụng nhiều vùng chứa các đối tượng tương tự
các hoạt động tương tự hoặc giống hệt nhau có thể được thực hiện.

3. API trợ giúp không chung chung; nó không cố gắng tối đa hóa việc tái sử dụng mã. Vì thế,
các cấu trúc lập trình như tính đa hình và các mẫu giúp tái sử dụng mã được
không phổ biến như vậy. Ví dụ: có các trình trợ giúp CsmaNetDevice riêng biệt và
Trình trợ giúp PointToPointNetDevice nhưng chúng không xuất phát từ cơ sở NetDevice chung
lớp học.

4. API trợ giúp thường hoạt động với các đối tượng được phân bổ theo ngăn xếp (so với phân bổ theo đống). Vì
một số chương trình, ns-3 người dùng có thể không cần phải lo lắng về bất kỳ việc Tạo hoặc tạo đối tượng cấp thấp nào
xử lý Ptr; họ có thể thực hiện với các thùng chứa đối tượng và các trình trợ giúp được phân bổ theo ngăn xếp
hoạt động trên chúng.

API trợ giúp thực sự chỉ nhằm mục đích tạo ra ns-3 chương trình dễ viết và đọc hơn mà không cần
lấy đi sức mạnh của giao diện cấp thấp. Phần còn lại của chương này cung cấp một số
ví dụ về các quy ước lập trình của API trợ giúp.

Làm Lô đất sử dụng các gnuplot Lớp
Có 2 phương pháp phổ biến để vẽ đồ thị bằng cách sử dụng ns-3 và gnuplot (-
http://www.gnuplot.info):

1. Tạo tệp điều khiển gnuplot bằng cách sử dụng ns-3lớp Gnuplot của.

2. Tạo tệp dữ liệu gnuplot bằng cách sử dụng các giá trị được tạo bởi ns-3.

Phần này nói về phương pháp 1, tức là về cách vẽ đồ thị bằng cách sử dụng ns-3của Gnuplot
lớp học. Nếu bạn quan tâm đến phương pháp 2, hãy xem tiểu mục "Ví dụ thực tế" trong phần
Phần "Truy tìm" trong ns-3 Hướng dẫn.

Tạo Lô đất Sử dụng các gnuplot Lớp
Các bước sau đây phải được thực hiện để tạo một biểu đồ bằng cách sử dụng ns-3lớp Gnuplot của:

1. Sửa đổi mã của bạn để sử dụng lớp Gnuplot và các chức năng của nó.

2. Chạy mã của bạn để tạo tệp điều khiển gnuplot.

3. Gọi gnuplot bằng tên của tệp điều khiển gnuplot.

4. Xem tệp đồ họa được tạo trong trình xem đồ họa yêu thích của bạn.

Xem mã từ các ô ví dụ được thảo luận bên dưới để biết chi tiết về bước 1.

An Ví dụ chương trình việc này Sử dụng các gnuplot Lớp
Một chương trình ví dụ sử dụng ns-3Lớp Gnuplot của có thể được tìm thấy ở đây:

src/stats/examples/gnuplot-example.cc

Để chạy ví dụ này, hãy làm như sau:

$ ./vỏ waf
$ cd build/debug/src/stats/examples
$ ./gnuplot-example

Điều này sẽ tạo ra các tệp điều khiển gnuplot sau trong thư mục chứa ví dụ
được đặt tại:

cốt truyện-2d.plt
cốt truyện-2d-với-error-bars.plt
cốt truyện-3d.plt

Để xử lý các tệp điều khiển gnuplot này, hãy làm như sau:

$ gnuplot cốt truyện-2d.plt
$ gnuplot cốt truyện-2d-với-error-bars.plt
$ gnuplot cốt truyện-3d.plt

Điều này sẽ tạo ra các tệp đồ họa sau trong thư mục chứa ví dụ
xác định vị trí:

cốt truyện-2d.png
cốt truyện-2d-với-error-bars.png
cốt truyện-3d.png

Bạn có thể xem các tệp đồ họa này trong trình xem đồ họa yêu thích của mình. Nếu bạn có gimp
được cài đặt trên máy của bạn, chẳng hạn, bạn có thể thực hiện việc này:

$ gimp cốt truyện-2d.png
$ gimp lô-2d-with-error-bars.png
$ gimp cốt truyện-3d.png

An Ví dụ 2 chiều Âm mưu
Đồ thị 2 chiều sau đây
[hình ảnh]

được tạo bằng mã sau từ gnuplot-example.cc:

sử dụng namespace std;

chuỗi fileNameWithNoExtension = "plot-2d";
chuỗi đồ họaFileName = fileNameWithNoExtension + ".png";
chuỗi cốt truyệnFileName = fileNameWithNoExtension + ".plt";
chuỗi cốt truyệnTitle = "Âm mưu 2-D";
string dataTitle = "Dữ liệu 2-D";

// Khởi tạo cốt truyện và đặt tiêu đề cho nó.
Cốt truyện Gnuplot (graphicsFileName);
cốt truyện.SetTitle (plotTitle);

// Tạo tệp đồ họa mà tệp cốt truyện sẽ tạo khi nó
// được sử dụng với Gnuplot, là file PNG.
cốt truyện.SetTerminal ("png");

// Đặt nhãn cho mỗi trục.
cốt truyện.SetLegend ("Giá trị X", "Giá trị Y");

// Đặt phạm vi cho trục x.
cốt truyện.AppendExtra ("đặt xrange [-6:+6]");

// Khởi tạo tập dữ liệu, đặt tiêu đề và đặt các điểm
// được vẽ cùng với các đường kết nối.
Bộ dữ liệu Gnuplot2dDataset;
tập dữ liệu.SetTitle (dataTitle);
tập dữ liệu.SetStyle (Gnuplot2dDataset::LINES_POINTS);

gấp đôi x;
y gấp đôi;

// Tạo tập dữ liệu 2-D.
với (x = -5.0; x <= +5.0; x += 1.0)
{
// Tính đường cong 2-D
//
// 2
// y = x .
//
y = x * x;

// Thêm điểm này.
tập dữ liệu.Thêm (x, y);
}

// Thêm tập dữ liệu vào biểu đồ.
cốt truyện.AddDataset (bộ dữ liệu);

// Mở file cốt truyện.
ofstream storyFile (plotFileName.c_str());

// Viết file cốt truyện.
cốt truyện.GenerateOutput (plotFile);

// Đóng file cốt truyện.
cốt truyệnFile.close ();

An Ví dụ 2 chiều Âm mưu với lỗi Bars
Biểu đồ 2 chiều sau đây có các thanh lỗi theo hướng x và y
[hình ảnh]

được tạo bằng mã sau từ gnuplot-example.cc:

sử dụng namespace std;

chuỗi fileNameWithNoExtension = "plot-2d-with-error-bars";
chuỗi đồ họaFileName = fileNameWithNoExtension + ".png";
chuỗi cốt truyệnFileName = fileNameWithNoExtension + ".plt";
stringplotTitle = "Biểu đồ 2-D có thanh lỗi";
string dataTitle = "Dữ liệu 2-D có thanh lỗi";

// Khởi tạo cốt truyện và đặt tiêu đề cho nó.
Cốt truyện Gnuplot (graphicsFileName);
cốt truyện.SetTitle (plotTitle);

// Tạo tệp đồ họa mà tệp cốt truyện sẽ tạo khi nó
// được sử dụng với Gnuplot, là file PNG.
cốt truyện.SetTerminal ("png");

// Đặt nhãn cho mỗi trục.
cốt truyện.SetLegend ("Giá trị X", "Giá trị Y");

// Đặt phạm vi cho trục x.
cốt truyện.AppendExtra ("đặt xrange [-6:+6]");

// Khởi tạo tập dữ liệu, đặt tiêu đề và đặt các điểm
// được vẽ không có đường kết nối.
Bộ dữ liệu Gnuplot2dDataset;
tập dữ liệu.SetTitle (dataTitle);
tập dữ liệu.SetStyle (Gnuplot2dDataset::POINTS);

// Làm cho tập dữ liệu có các thanh lỗi theo cả hai hướng x và y.
tập dữ liệu.SetErrorBars (Gnuplot2dDataset::XY);

gấp đôi x;
xErrorDelta gấp đôi;
y gấp đôi;
nhân đôi yErrorDelta;

// Tạo tập dữ liệu 2-D.
với (x = -5.0; x <= +5.0; x += 1.0)
{
// Tính đường cong 2-D
//
// 2
// y = x .
//
y = x * x;

// Làm cho độ bất định theo hướng x không đổi và tạo
// độ không đảm bảo theo hướng y là một phần không đổi của
// giá trị của y.
xErrorDelta = 0.25;
yErrorDelta = 0.1 * y;

// Thêm điểm này với độ không chắc chắn ở cả x và y
// phương hướng.
tập dữ liệu.Add (x, y, xErrorDelta, yErrorDelta);
}

// Thêm tập dữ liệu vào biểu đồ.
cốt truyện.AddDataset (bộ dữ liệu);

// Mở file cốt truyện.
ofstream storyFile (plotFileName.c_str());

// Viết file cốt truyện.
cốt truyện.GenerateOutput (plotFile);

// Đóng file cốt truyện.
cốt truyệnFile.close ();

An Ví dụ 3 chiều Âm mưu
Đồ thị 3 chiều sau đây
[hình ảnh]

được tạo bằng mã sau từ gnuplot-example.cc:

sử dụng namespace std;

chuỗi fileNameWithNoExtension = "plot-3d";
chuỗi đồ họaFileName = fileNameWithNoExtension + ".png";
chuỗi cốt truyệnFileName = fileNameWithNoExtension + ".plt";
chuỗi cốt truyệnTitle = "Âm mưu 3-D";
string dataTitle = "Dữ liệu 3-D";

// Khởi tạo cốt truyện và đặt tiêu đề cho nó.
Cốt truyện Gnuplot (graphicsFileName);
cốt truyện.SetTitle (plotTitle);

// Tạo tệp đồ họa mà tệp cốt truyện sẽ tạo khi nó
// được sử dụng với Gnuplot, là file PNG.
cốt truyện.SetTerminal ("png");

// Xoay đồ thị 30 độ quanh trục x rồi xoay
// vẽ đồ thị 120 độ quanh trục z mới.
cốt truyện.AppendExtra ("đặt chế độ xem 30, 120, 1.0, 1.0");

// Đặt số 0 cho trục z nằm trong mặt phẳng trục x và trục y.
cốt truyện.AppendExtra ("đặt ticslevel 0");

// Đặt nhãn cho mỗi trục.
cốt truyện.AppendExtra ("đặt xlabel 'Giá trị X'");
cốt truyện.AppendExtra ("đặt ylabel 'Giá trị Y'");
cốt truyện.AppendExtra ("đặt zlabel 'Giá trị Z'");

// Đặt phạm vi cho trục x và y.
cốt truyện.AppendExtra ("đặt xrange [-5:+5]");
cốt truyện.AppendExtra ("đặt yrange [-5:+5]");

// Khởi tạo tập dữ liệu, đặt tiêu đề và đặt các điểm
// được kết nối bằng các đường.
Bộ dữ liệu Gnuplot3dDataset;
tập dữ liệu.SetTitle (dataTitle);
tập dữ liệu.SetStyle ("có dòng");

gấp đôi x;
y gấp đôi;
z đôi;

// Tạo tập dữ liệu 3-D.
với (x = -5.0; x <= +5.0; x += 1.0)
{
với (y = -5.0; y <= +5.0; y += 1.0)
{
// Tính toán bề mặt 3-D
//
// 2 2
// z = x * y .
//
z = x * x * y * y;

// Thêm điểm này.
tập dữ liệu.Thêm (x, y, z);
}

// Cần có dòng trống ở cuối mỗi dữ liệu của giá trị x
// điểm để lưới bề mặt 3-D hoạt động.
tập dữ liệu.AddEmptyLine ();
}

// Thêm tập dữ liệu vào biểu đồ.
cốt truyện.AddDataset (bộ dữ liệu);

// Mở file cốt truyện.
ofstream storyFile (plotFileName.c_str());

// Viết file cốt truyện.
cốt truyện.GenerateOutput (plotFile);

// Đóng file cốt truyện.
cốt truyệnFile.close ();

Sử dụng Python đến chạy ns-3
Các ràng buộc Python cho phép mã C++ trong ns-3 được gọi từ Python.

Chương này hướng dẫn bạn cách tạo tập lệnh Python có thể chạy ns-3 và cả
quá trình tạo liên kết Python cho C++ ns-3 mô-đun.

Giới thiệu
Mục tiêu của các ràng buộc Python dành cho ns-3 là hai lần:

1. Cho phép lập trình viên viết các tập lệnh mô phỏng hoàn chỉnh bằng Python (-
http://www.python.org);

2. Nguyên mẫu các mô hình mới (ví dụ: giao thức định tuyến).

Hiện tại, trọng tâm chính của các ràng buộc là mục tiêu đầu tiên, nhưng mục tiêu thứ hai
mục tiêu cuối cùng cũng sẽ được hỗ trợ. Các ràng buộc Python cho ns-3 đang được phát triển
sử dụng một công cụ mới có tên PyBindGen (http://code.google.com/p/pybindgen).

An Ví dụ Python Script việc này Chạy ns-3
Đây là một số mã ví dụ được viết bằng Python và chạy ns-3, được viết
trong C++. Ví dụ Python này có thể được tìm thấy trong ví dụ/hướng dẫn/first.py:

nhập ns.applications
nhập ns.core
nhập ns.internet
nhập ns.network
nhập ns.point_to_point

ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO)
ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO)

nút = ns.network.NodeContainer()
nút.Tạo(2)

pointToPoint = ns.point_to_point.PointToPointHelper()
pointToPoint.SetDeviceAttribution ("DataRate", ns.core.StringValue ("5Mbps"))
pointToPoint.SetChannelAttribution ("Độ trễ", ns.core.StringValue ("2ms"))

thiết bị = pointToPoint.Install(nodes)

ngăn xếp = ns.internet.InternetStackHelper()
stack.Install(nút)

địa chỉ = ns.internet.Ipv4AddressHelper()
address.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0"))

giao diện = địa chỉ.Assign (thiết bị);

echoServer = ns.applications.UdpEchoServerHelper(9)

serverApps = echoServer.Install(node.Get(1))
serverApps.Start(ns.core.Seconds(1.0))
serverApps.Stop(ns.core.Seconds(10.0))

echoClient = ns.appluggest.UdpEchoClientHelper(giao diện.GetAddress(1), 9)
echoClient.SetAttribution ("MaxPackets", ns.core.UintegerValue(1))
echoClient.SetAttribution("Khoảng thời gian", ns.core.TimeValue(ns.core.Seconds (1.0)))
echoClient.SetAttribution ("Kích thước gói", ns.core.UintegerValue(1024))

clientApps = echoClient.Install(node.Get(0))
clientApps.Start(ns.core.Seconds(2.0))
clientApps.Stop(ns.core.Seconds(10.0))

ns.core.Simulator.Run()
ns.core.Simulator.Destroy()

Chạy Python Kịch bản
waf chứa một số tùy chọn tự động cập nhật đường dẫn python để tìm ns3
mô-đun. Để chạy các chương trình mẫu, có hai cách sử dụng waf để giải quyết vấn đề này. Một
là chạy một shell waf; ví dụ:

$ ./waf --shell
$ ví dụ về python/wireless/mixed-wireless.py

và cách khác là sử dụng tùy chọn --pyrun để waf:

$ ./waf --pyrun ví dụ/wireless/mixed-wireless.py

Để chạy tập lệnh python trong trình gỡ lỗi C:

$ ./waf --shell
$ gdb --args ví dụ về python/wireless/mixed-wireless.py

Để chạy tập lệnh Python của riêng bạn gọi ns-3 và nó có con đường này,
/path/to/your/example/my-script.py, làm như sau:

$ ./waf --shell
$ python /path/to/your/example/my-script.py

Hãy cẩn thận
Các ràng buộc Python cho ns-3 là một công việc đang được tiến hành và một số hạn chế đã được biết đến bởi
nhà phát triển. Một số hạn chế (không phải tất cả) được liệt kê ở đây.

Không đầy đủ Toàn Diện
Trước hết, hãy nhớ rằng không phải 100% API đều được hỗ trợ bằng Python. Một số
lý do là:

1. một số API liên quan đến con trỏ, đòi hỏi kiến ​​thức về loại bộ nhớ
truyền ngữ nghĩa (ai sở hữu bộ nhớ nào). Kiến thức như vậy không phải là một phần của chức năng
chữ ký và được ghi lại hoặc đôi khi thậm chí không được ghi lại. Chú thích là
cần thiết để ràng buộc các chức năng đó;

2. Đôi khi một kiểu dữ liệu cơ bản bất thường hoặc cấu trúc C++ được sử dụng nhưng chưa được
được hỗ trợ bởi PyBindGen;

3. GCC-XML không báo cáo các lớp dựa trên mẫu trừ khi chúng được khởi tạo.

Hầu hết các API còn thiếu đều có thể được hoàn thiện nếu có đủ thời gian, sự kiên nhẫn và kiến ​​thức chuyên môn cũng như
có thể sẽ được gói lại nếu báo cáo lỗi được gửi. Tuy nhiên, đừng gửi báo cáo lỗi
nói "ràng buộc chưa đầy đủ", vì chúng tôi không có nhân lực để hoàn thành 100% công việc
ràng buộc.

Chuyển đổi Người xây dựng
Chuyển đổi người xây dựng chưa được PyBindGen hỗ trợ đầy đủ và chúng luôn hoạt động như
các hàm tạo rõ ràng khi dịch API sang Python. Ví dụ: trong C++ bạn có thể làm
điều này:

Ipv4AddressHelper ipAddrs;
ipAddrs.SetBase ("192.168.0.0", "255.255.255.0");
ipAddrs.Assign (thiết bị xương sống);

Trong Python, hiện tại bạn phải làm:

ipAddrs = ns3.Ipv4AddressHelper()
ipAddrs.SetBase(ns3.Ipv4Address("192.168.0.0"), ns3.Ipv4Mask("255.255.255.0"))
ipAddrs.Assign(backboneDevices)

Dòng lệnh
Dòng lệnh::AddValue() hoạt động khác trong Python so với trong ns-3. Trong Python,
tham số đầu tiên là một chuỗi đại diện cho tên tùy chọn dòng lệnh. Khi tùy chọn
được đặt, một thuộc tính có cùng tên với tên tùy chọn sẽ được đặt trên Dòng lệnh()
sự vật. Ví dụ:

NUM_NODES_SIDE_DEFAULT = 3

cmd = ns3.CommandLine()

cmd.NumNodesSide = Không
cmd.AddValue("NumNodesSide", "Số nút bên lưới (tổng số nút sẽ là số này bình phương)")

cmd.Parse(argv)

[...]

nếu cmd.NumNodesSide là Không có:
num_nodes_side = NUM_NODES_SIDE_DEFAULT
khác:
num_nodes_side = int(cmd.NumNodesSide)

Truy tìm
Theo dõi dựa trên cuộc gọi lại chưa được hỗ trợ đúng cách cho Python, vì tính năng mới ns-3 API cần
được cung cấp để được hỗ trợ.

Việc ghi tệp Pcap được hỗ trợ thông qua API thông thường.

Truy tìm Ascii được hỗ trợ kể từ ns-3.4 thông qua API C++ thông thường được dịch sang Python.
Tuy nhiên, việc theo dõi ascii yêu cầu tạo một đối tượng ostream để chuyển vào ascii
các phương pháp truy vết. Trong Python, C++ std::ofstream đã được gói gọn ở mức tối thiểu để cho phép
cái này. Ví dụ:

ascii = ns3.ofstream("wifi-ap.tr") # tạo tập tin
ns3.YansWifiPhyHelper.EnableAsciiAll(ascii)
ns3.Simulator.Run()
ns3.Simulator.Destroy()
ascii.close() # đóng tệp

Có một lưu ý: bạn không được phép thu thập đối tượng tệp trong khi ns-3
vẫn đang sử dụng nó. Điều đó có nghĩa là biến 'ascii' ở trên không được phép đi
ngoài phạm vi nếu không chương trình sẽ bị lỗi.

Cygwin giới hạn
Các ràng buộc Python không hoạt động trên Cygwin. Điều này là do lỗi gccxml.

Bạn có thể thoát khỏi nó bằng cách quét lại các định nghĩa API từ bên trong cygwin
môi trường (./waf --python-scan). Tuy nhiên, giải pháp khả thi nhất có thể sẽ phải
là chúng tôi vô hiệu hóa các liên kết python trong CygWin.

Nếu bạn thực sự quan tâm đến các ràng buộc Python trên Windows, hãy thử xây dựng bằng mingw và gốc
thay vào đó là trăn. Hoặc nếu không, để xây dựng mà không có liên kết python, hãy tắt liên kết python trong
Giai đoạn cấu hình:

$ ./waf cấu hình --disable-python

Đang làm việc với Python Bindings
Hiện tại có hai loại liên kết Python trong ns-3:

1. Các liên kết nguyên khối chứa các định nghĩa API cho tất cả các mô-đun và có thể được tìm thấy trong
một thư mục duy nhất, ràng buộc/trăn.

2. Các liên kết mô-đun chứa các định nghĩa API cho một mô-đun duy nhất và có thể được tìm thấy trong mỗi mô-đun.
mô-đun ràng buộc thư mục.

Python Bindings Quy trình làm việc
Quá trình xử lý các ràng buộc Python như sau:

1. Định kỳ nhà phát triển sử dụng GCC-XML (http://www.gccxml.org) quét API dựa trên
tập lệnh lưu định nghĩa API được quét dưới dạng liên kết/python/ns3_module_*.py các tập tin
hoặc dưới dạng tệp Python trong mỗi mô-đun' ràng buộc danh mục. Những tập tin này được lưu giữ dưới
kiểm soát phiên bản chính ns-3 kho;

2. Các nhà phát triển khác sao chép kho lưu trữ và sử dụng các định nghĩa API đã được quét;

3. Khi cấu hình ns-3, pybindgen sẽ được tự động tải xuống nếu chưa có
Cài đặt. Phát hành ns-3 tarball sẽ gửi một bản sao của pybindgen.

Nếu có vấn đề xảy ra khi biên dịch các ràng buộc Python và bạn chỉ muốn bỏ qua chúng
và tiếp tục với C++, bạn có thể tắt Python bằng:

$ ./waf --disable-python

Hướng Dẫn cho Xử lý Mới Các Tập Tin or Thay đổi API
Vì vậy, bạn đã thay đổi hiện tại ns-3 Các liên kết API và Python không còn biên dịch nữa? LÀM
đừng tuyệt vọng, bạn có thể quét lại các ràng buộc để tạo các ràng buộc mới phản ánh những thay đổi
đến ns-3 API.

Tùy thuộc vào việc bạn đang sử dụng liên kết nguyên khối hay mô-đun, hãy xem các cuộc thảo luận bên dưới để biết
tìm hiểu cách quét lại các ràng buộc Python của bạn.

Monolithic Python Bindings
Quét (scanning) các Monolithic Python Bindings
Để quét các liên kết Python nguyên khối, hãy làm như sau:

$ ./waf --python-scan

Cơ quan of các Monolithic Python Bindings
Các định nghĩa API Python nguyên khối được sắp xếp như sau. Cho mỗi ns-3 mô-đun
, tập tin liên kết/python/ns3_module_ .py mô tả API của nó. Mỗi cái đó
các tập tin có 3 chức năng cấp cao nhất:

1. def đăng ký_types(mô-đun)(): chức năng này đảm nhiệm việc đăng ký các loại mới (ví dụ:
Các lớp C++, enum) được định nghĩa trong mô-đun tha;

2. def đăng ký_phương thức(mô-đun)(): hàm này gọi, cho mỗi lớp , khác
hàm register_methods_Ns3 (mô-đun). Các hàm sau này thêm phương thức
định nghĩa cho từng lớp;

3. def đăng ký_hàm(mô-đun)(): chức năng này đăng ký ns-3 các chức năng thuộc về
mô-đun đó.

Modular Python Bindings
Giới thiệu chung
Kể từ ns 3.11, các liên kết mô-đun đang được thêm vào, song song với nguyên khối cũ
ràng buộc.

Các liên kết python mới được tạo vào một không gian tên 'ns', thay vì 'ns3' như cũ
ràng buộc. Ví dụ:

từ nút nhập ns.network
n1 = Nút()

Với các ràng buộc Python mô-đun:

1. Có một mô-đun mở rộng Python riêng cho mỗi mô-đun ns-3 môđun;

2. Việc quét các định nghĩa API (apidefs) được thực hiện trên cơ sở từng mô-đun ns;

3. Các tệp apidefs của mỗi mô-đun được lưu trữ trong thư mục con 'ràng buộc' của mô-đun
danh mục;

Quét (scanning) các Modular Python Bindings
Ví dụ: để quét các liên kết Python mô-đun cho mô-đun lõi, hãy làm như sau:

$ ./waf --apiscan=core

Để quét các liên kết Python mô-đun cho tất cả các mô-đun, hãy làm như sau:

$ ./waf --apiscan=all

Tạo a Mới Mô-đun
Nếu bạn đang thêm một mô-đun mới, các liên kết Python sẽ tiếp tục biên dịch nhưng sẽ không
che mô-đun mới.

Để bao gồm một mô-đun mới, bạn phải tạo một liên kết/python/ns3_module_ .py tập tin,
tương tự như những gì được mô tả trong các phần trước và đăng ký nó vào biến
LOCAL_MODULES() in liên kết/python/ns3modulegen.py

Thêm Modular Bindings Đến A Hiện tại Mô-đun
Để thêm hỗ trợ cho các ràng buộc mô-đun vào một ns-3 mô-đun, chỉ cần thêm vào như sau
dòng vào hàm wscript build() của nó:

bld.ns3_python_binds()

Cơ quan of các Modular Python Bindings
src/ /ràng buộc thư mục có thể chứa các tệp sau, một số trong số chúng
không bắt buộc:

· callbacks_list.py: đây là file scan, KHÔNG CHẠM. Chứa danh sách các
Gọi lại<...> phiên bản mẫu được tìm thấy trong các tiêu đề được quét;

· modulegen__gcc_LP64.py: đây là file scan, KHÔNG CHẠM. Định nghĩa API được quét
cho kiến ​​trúc GCC, LP64 (64-bit)

· modulegen__gcc_ILP32.py: đây là file scan, KHÔNG CHẠM. Định nghĩa API được quét
cho kiến ​​trúc GCC, ILP32 (32-bit)

· modulegen_customizations.py: bạn có thể tùy ý thêm tệp này để tùy chỉnh
tạo mã pybindgen

· quét-header.h: bạn có thể tùy ý thêm tệp này để tùy chỉnh tệp tiêu đề nào được quét
cho mô-đun. Về cơ bản tập tin này được quét thay vì ns3/ -module.h.
Thông thường, câu lệnh đầu tiên là #include "ns3/ -module.h", cùng với một số thứ khác
công cụ buộc phải khởi tạo mẫu;

· module_helpers.cc: bạn có thể thêm các tệp bổ sung, chẳng hạn như tệp này, để được liên kết với python
mô-đun mở rộng, nhưng chúng phải được đăng ký trong wscript. Nhìn vào
src/core/wscript để biết ví dụ về cách thực hiện;

· .py: nếu tệp này tồn tại, nó sẽ trở thành mô-đun python "giao diện người dùng" cho ns3
mô-đun và mô-đun mở rộng (tệp .so) trở thành _ .so thay vì .Vì thế.
Các Tệp .py phải nhập tất cả các ký hiệu từ mô-đun _ (cái này nhiều hơn
phức tạp hơn âm thanh của nó, xem ví dụ về src/core/binds/core.py), sau đó có thể thêm
một số định nghĩa thuần Python bổ sung.

Xem thêm Thông tin cho Các nhà phát triển
Nếu bạn là nhà phát triển và cần thêm thông tin về ns-3các ràng buộc Python của, vui lòng xem
Python Bindings wiki trang.

Kiểm tra
Giới thiệu chung
Tài liệu này liên quan đến việc kiểm tra và xác nhận tính hợp lệ của ns-3 phần mềm.

Tài liệu này cung cấp

· Nền tảng về thuật ngữ và kiểm thử phần mềm (Chương 2);

· mô tả khung thử nghiệm ns-3 (Chương 3);

· hướng dẫn cho các nhà phát triển mô hình hoặc những người đóng góp mô hình mới về cách viết bài kiểm tra (Chương
4);

Tóm lại, ba chương đầu tiên nên được đọc bởi các nhà phát triển và cộng tác viên của ns, những người
cần hiểu cách đóng góp mã kiểm tra và các chương trình đã được xác thực và phần còn lại
của tài liệu cung cấp không gian để mọi người báo cáo về những khía cạnh nào của các mô hình được chọn
đã được xác thực.

Tiểu sử
T chương có thể be bỏ qua by độc giả quen với các cơ bản of phần mềm thử nghiệm.

Viết phần mềm không có lỗi là một đề xuất khó khăn. Có rất nhiều kích thước của
vấn đề và có nhiều nhầm lẫn về ý nghĩa của các thuật ngữ khác nhau trong
bối cảnh khác nhau. Chúng tôi nhận thấy thật đáng để dành chút thời gian xem xét
chủ đề và định nghĩa một số thuật ngữ.

Kiểm thử phần mềm có thể được định nghĩa một cách lỏng lẻo là quá trình thực hiện một chương trình với
mục đích tìm lỗi. Khi một người bước vào một cuộc thảo luận liên quan đến kiểm thử phần mềm, nó
nhanh chóng trở nên rõ ràng rằng có nhiều lối tư duy riêng biệt mà người ta có thể
tiếp cận chủ đề.

Ví dụ: người ta có thể chia quy trình thành các danh mục chức năng rộng như
''kiểm tra tính đúng đắn'' ''kiểm tra hiệu suất'' ''kiểm tra độ tin cậy'' và ''bảo mật
kiểm tra.'' Một cách khác để xem xét vấn đề là theo vòng đời: ''kiểm tra yêu cầu''
''thử nghiệm thiết kế'' ''thử nghiệm chấp nhận'' và ''thử nghiệm bảo trì.'' Một góc nhìn khác
là theo phạm vi của hệ thống được thử nghiệm. Trong trường hợp này người ta có thể nói đến ''kiểm thử đơn vị''
''thử nghiệm thành phần'' ''thử nghiệm tích hợp'' và ''thử nghiệm hệ thống.'' Các thuật ngữ này là
cũng không được tiêu chuẩn hóa dưới bất kỳ hình thức nào, do đó ''kiểm tra bảo trì'' và ''hồi quy
testing'' có thể được nghe thay thế cho nhau. Ngoài ra, những thuật ngữ này thường bị sử dụng sai.

Ngoài ra còn có một số cách tiếp cận triết học khác nhau để kiểm thử phần mềm. Vì
Ví dụ, một số tổ chức ủng hộ việc viết chương trình kiểm tra trước khi thực sự triển khai
phần mềm mong muốn, mang lại ''sự phát triển dựa trên thử nghiệm''. Một số tổ chức ủng hộ
thử nghiệm từ góc độ khách hàng càng sớm càng tốt, song song với
quá trình phát triển linh hoạt: ''kiểm tra sớm và kiểm tra thường xuyên.'' Điều này đôi khi được gọi là
''thử nghiệm linh hoạt.'' Có vẻ như có ít nhất một cách tiếp cận để thử nghiệm cho mọi
phương pháp phát triển.

ns-3 dự án không nhằm mục đích vận động cho bất kỳ quy trình nào trong số này, mà là
toàn bộ dự án có các yêu cầu giúp cung cấp thông tin cho quá trình thử nghiệm.

Giống như tất cả các sản phẩm phần mềm lớn, ns-3 có một số phẩm chất cần phải có để
sản phẩm sẽ thành công. Từ góc độ thử nghiệm, một số phẩm chất này phải được
đã giải quyết được điều đó ns-3 phải ''chính xác'' ''mạnh mẽ'' ''hiệu quả'' và
''có thể duy trì được.'' Lý tưởng nhất là nên có số liệu cho từng thứ nguyên này
được kiểm tra bằng các cuộc kiểm tra để xác định khi nào sản phẩm không đáp ứng được mong đợi /
yêu cầu.

Tính đúng đắn
Mục đích cơ bản của việc kiểm tra là xác định xem một phần mềm có hoạt động
''chính xác.'' Vì ns-3 điều này có nghĩa là nếu chúng ta mô phỏng một cái gì đó thì việc mô phỏng sẽ
trình bày một cách trung thực một số thực thể hoặc quy trình vật lý với độ chính xác và quy định cụ thể.
độ chính xác.

Hóa ra có hai quan điểm mà người ta có thể xem xét tính đúng đắn.
Việc xác minh rằng một mô hình cụ thể được triển khai theo đặc điểm kỹ thuật của nó là
gọi một cách tổng quát xác minh. Quá trình quyết định rằng mô hình là đúng cho
mục đích sử dụng của nó được gọi chung là xác nhận.

THẨM ĐỊNH Xác minh
Một mô hình máy tính là một biểu diễn toán học hoặc logic của một cái gì đó. Nó có thể
tượng trưng cho một chiếc xe, một con voi (xem David của Harel nói chuyện về người mẫu an voi at
SIMUCông cụ 2009hoặc card mạng. Các mô hình cũng có thể biểu diễn các tiến trình như toàn cục
sự nóng lên, lưu lượng giao thông trên đường cao tốc hoặc thông số kỹ thuật của giao thức mạng. Các mô hình có thể được
sự biểu diễn hoàn toàn trung thực của một đặc tả quy trình logic, nhưng chúng
nhất thiết không bao giờ có thể mô phỏng hoàn toàn một đối tượng hoặc quá trình vật lý. Trong hầu hết các trường hợp, một
số lượng đơn giản hóa được thực hiện đối với mô hình để thực hiện mô phỏng tính toán
dễ điều khiển.

Mỗi mô hình có một mục tiêu hệ thống mà nó đang cố gắng mô phỏng. Bước đầu tiên trong
Việc tạo ra một mô hình mô phỏng là xác định hệ thống mục tiêu này cũng như mức độ chi tiết và
độ chính xác mà mô phỏng mong muốn tái tạo. Trong trường hợp của một quá trình logic,
hệ thống đích có thể được xác định là ''TCP như được định nghĩa bởi RFC 793.'' Trong trường hợp này, nó
có lẽ sẽ mong muốn tạo ra một mô hình tái tạo hoàn toàn và trung thực RFC
793. Trong trường hợp của một quá trình vật lý, điều này sẽ không thể thực hiện được. Ví dụ, nếu bạn
muốn mô phỏng một card mạng không dây, bạn có thể xác định rằng bạn cần, '' một
triển khai chính xác ở cấp độ MAC của thông số kỹ thuật 802.11 và […] không quá chậm
Mô hình cấp độ PHY của thông số kỹ thuật 802.11a.''

Một khi điều này được thực hiện, người ta có thể phát triển một mô hình trừu tượng của hệ thống đích. Đây là
điển hình là một bài tập trong việc quản lý sự cân bằng giữa độ phức tạp, yêu cầu về nguồn lực
và độ chính xác. Quá trình phát triển một mô hình trừu tượng được gọi là kiểu mẫu
trình độ chuyên môn trong văn học. Trong trường hợp giao thức TCP, quá trình này dẫn đến một
thiết kế cho một tập hợp các đối tượng, các tương tác và hành vi sẽ thực hiện đầy đủ
RFC 793 trong ns-3. Trong trường hợp card không dây, quá trình này dẫn đến một số
sự cân bằng để cho phép lớp vật lý được mô phỏng và thiết kế thiết bị mạng
và kênh cho ns-3, cùng với các đối tượng, sự tương tác và hành vi mong muốn.

Mô hình trừu tượng này sau đó được phát triển thành một ns-3 mô hình thực hiện trừu tượng
mô hình như một chương trình máy tính. Quá trình thực hiện đạt được sự đồng thuận với
mô hình trừu tượng được gọi là kiểu mẫu xác minh trong văn học.

Quá trình cho đến nay là vòng lặp mở. Việc còn lại là đưa ra quyết định rằng ns-3 đã cho
mô hình có mối liên hệ nào đó với thực tế nào đó -- rằng mô hình là sự thể hiện chính xác của
một hệ thống thực, dù là một quá trình logic hay một thực thể vật lý.

Nếu người ta định sử dụng mô hình mô phỏng để thử và dự đoán hệ thống thực nào đó sẽ hoạt động như thế nào
hành xử thì phải có lý do nào đó để tin vào kết quả của bạn -- tức là người ta có thể tin vào điều đó không?
một suy luận được thực hiện từ mô hình sẽ chuyển thành một dự đoán chính xác cho hệ thống thực.
Quá trình làm cho hành vi của mô hình ns-3 phù hợp với hệ thống mục tiêu mong muốn
hành vi được xác định bởi quá trình đánh giá mô hình được gọi là kiểu mẫu xác nhận trong
văn học. Trong trường hợp triển khai TCP, bạn có thể muốn so sánh hành vi của
mô hình TCP ns-3 của bạn tới một số triển khai tham chiếu để xác thực mô hình của bạn. TRONG
trường hợp mô phỏng lớp vật lý không dây, bạn có thể muốn so sánh hành vi của
mô hình của bạn với mô hình của phần cứng thực trong cài đặt được kiểm soát,

ns-3 môi trường thử nghiệm cung cấp các công cụ cho phép xác nhận cả mô hình và
thử nghiệm và khuyến khích công bố kết quả xác nhận.

Độ bền
Độ bền là khả năng chịu được áp lực hoặc thay đổi của môi trường,
đầu vào hoặc tính toán, v.v. Một hệ thống hoặc thiết kế được coi là ''mạnh mẽ'' nếu nó có thể giải quyết được những vấn đề đó
thay đổi với sự mất mát tối thiểu về chức năng.

Loại thử nghiệm này thường được thực hiện với trọng tâm cụ thể. Ví dụ như hệ thống như
toàn bộ có thể chạy trên nhiều cấu hình hệ thống khác nhau để chứng minh rằng nó có thể
thực hiện chính xác trong một số lượng lớn các môi trường.

Hệ thống cũng có thể bị căng thẳng do vận hành gần hoặc vượt quá công suất do tạo ra
hoặc mô phỏng sự cạn kiệt tài nguyên ở nhiều dạng khác nhau. Thể loại thử nghiệm này được gọi là
''bài kiểm tra về áp lực.''

Hệ thống và các thành phần của nó có thể phải trải qua cái gọi là ''thử nghiệm sạch'' để chứng minh
một kết quả tích cực -- đó là hệ thống hoạt động chính xác để đáp ứng với một lượng lớn
sự thay đổi của cấu hình dự kiến.

Hệ thống và các thành phần của nó cũng có thể phải trải qua ''kiểm tra bẩn'' để cung cấp đầu vào
nằm ngoài phạm vi dự kiến. Ví dụ: nếu một mô-đun mong đợi một chuỗi kết thúc bằng 0
biểu diễn một số nguyên, một bài kiểm tra bẩn có thể cung cấp một chuỗi ngẫu nhiên không kết thúc
ký tự để xác minh rằng hệ thống không gặp sự cố do kết quả đầu vào không mong muốn này.
Thật không may, việc phát hiện đầu vào ''bẩn'' như vậy và thực hiện các biện pháp phòng ngừa để đảm bảo
hệ thống không bị lỗi nghiêm trọng có thể đòi hỏi một lượng lớn chi phí phát triển.
Để giảm thời gian phát triển, một quyết định đã được đưa ra ngay từ đầu trong dự án là
giảm thiểu số lượng xác thực tham số và xử lý lỗi trong ns-3 cơ sở mã. Vì
vì lý do này, chúng tôi không dành nhiều thời gian cho việc kiểm tra bẩn -- nó sẽ chỉ phát hiện ra
kết quả của quyết định thiết kế mà chúng tôi biết mình đã thực hiện.

Chúng tôi muốn chứng minh rằng ns-3 phần mềm hoạt động trong một số điều kiện. Chúng tôi
mượn một vài định nghĩa để thu hẹp điều này một chút. Các miền of khả năng ứng dụng is
một tập hợp các điều kiện quy định mà mô hình đã được kiểm tra, so sánh với
thực tế trong phạm vi có thể và được đánh giá là phù hợp để sử dụng. Các phạm vi of chính xác là một
sự thống nhất giữa mô hình máy tính và thực tế trong phạm vi khả năng ứng dụng.

ns-3 môi trường kiểm thử cung cấp các công cụ cho phép thiết lập và chạy thử nghiệm
môi trường trên nhiều hệ thống (buildbot) và cung cấp các lớp để khuyến khích dọn dẹp
kiểm tra để xác minh hoạt động của hệ thống trên ''miền ứng dụng'' dự kiến
và ''phạm vi chính xác.''

Người biểu diễn
Được rồi, ''người biểu diễn'' không phải là một từ tiếng Anh thực sự. Tuy nhiên, đây là một chủ nghĩa mới rất súc tích
nó thường được sử dụng để mô tả những gì chúng ta muốn ns-3 là: mạnh mẽ và đủ nhanh để
hoàn thành công việc.

Đây thực sự là một chủ đề rộng lớn về kiểm tra hiệu suất phần mềm. Một trong những chìa khóa
những việc được thực hiện là so sánh hai hệ thống để tìm ra hệ thống nào hoạt động tốt hơn (xem
điểm chuẩn). Điều này được sử dụng để chứng minh rằng, ví dụ, ns-3 có thể thực hiện một loại cơ bản
mô phỏng ít nhất là nhanh như một công cụ cạnh tranh hoặc có thể được sử dụng để xác định các phần của
hệ thống hoạt động kém.

Trong tạp chí ns-3 khung thử nghiệm, chúng tôi cung cấp hỗ trợ về thời gian cho các loại thử nghiệm khác nhau.

Khả năng bảo trì
Một sản phẩm phần mềm phải có khả năng bảo trì được. Đây, một lần nữa, là một tuyên bố rất rộng, nhưng là một
khung kiểm tra có thể giúp thực hiện nhiệm vụ. Khi một mô hình đã được phát triển, xác nhận và
được xác minh, chúng tôi có thể thực hiện nhiều lần bộ thử nghiệm cho toàn bộ hệ thống để đảm bảo
rằng nó vẫn hợp lệ và được xác minh trong suốt thời gian tồn tại của nó.

Khi một tính năng ngừng hoạt động như dự định sau khi có một số thay đổi nào đó đối với hệ thống
tích hợp, nó được gọi chung là một hồi quy. Ban đầu thuật ngữ hồi quy
đề cập đến một sự thay đổi khiến một lỗi đã được sửa trước đó xuất hiện trở lại, nhưng thuật ngữ này có
được phát triển để mô tả bất kỳ loại thay đổi nào phá vỡ chức năng hiện có. Có nhiều
các loại hồi quy có thể xảy ra trong thực tế.

A địa phương hồi quy là một trong đó một thay đổi ảnh hưởng trực tiếp đến thành phần được thay đổi. Vì
Ví dụ: nếu một thành phần được sửa đổi để phân bổ và giải phóng bộ nhớ nhưng các con trỏ cũ vẫn
được sử dụng, thành phần đó sẽ bị lỗi.

A xa hồi quy là một trong đó sự thay đổi đối với một thành phần sẽ phá vỡ chức năng trong
thành phần khác. Điều này phản ánh sự vi phạm một điều khoản ngụ ý nhưng có thể không được công nhận
hợp đồng giữa các thành phần.

An lột mặt nạ hồi quy là một lỗi tạo ra tình huống trong đó một lỗi đã tồn tại trước đó
không có ảnh hưởng gì đột nhiên xuất hiện trong hệ thống. Điều này có thể đơn giản như việc tập thể dục
một đường dẫn mã lần đầu tiên.

A hiệu suất hồi quy là nguyên nhân khiến các yêu cầu về hiệu năng của hệ thống bị ảnh hưởng
bị vi phạm. Ví dụ: thực hiện một số công việc ở hàm cấp thấp có thể được lặp lại
số lần lớn có thể đột nhiên khiến hệ thống không thể sử dụng được từ một số khía cạnh nhất định.

ns-3 khung kiểm tra cung cấp các công cụ để tự động hóa quy trình được sử dụng để xác nhận và
xác minh mã trong các bộ kiểm tra hàng đêm để giúp nhanh chóng xác định các hồi quy có thể xảy ra.

Kiểm tra khuôn khổ
ns-3 bao gồm một công cụ lõi mô phỏng, một tập hợp các mô hình, chương trình ví dụ và thử nghiệm.
Theo thời gian, những người đóng góp mới sẽ đóng góp các mô hình, bài kiểm tra và ví dụ. Một chương trình thử nghiệm Python
test.py đóng vai trò là người quản lý thực hiện kiểm thử; test.py có thể chạy mã kiểm tra và các ví dụ để
tìm kiếm hồi quy, có thể xuất kết quả thành một số dạng và có thể quản lý mã
công cụ phân tích vùng phủ sóng. Trên hết, chúng tôi xếp lớp Buildbots được xây dựng tự động
robot thực hiện kiểm tra độ bền bằng cách chạy khung kiểm tra trên các hệ thống khác nhau
và với các tùy chọn cấu hình khác nhau.

BuildBot
Ở cấp độ cao nhất của thử nghiệm ns-3 là buildbots (robot xây dựng). Nếu bạn là
không quen với hệ thống này nhìn vào http://djmitche.github.com/buildbot/docs/0.7.11/.
Đây là một hệ thống tự động mã nguồn mở cho phép ns-3 được xây dựng lại và thử nghiệm từng
thời gian đã có điều gì đó thay đổi Bằng cách chạy buildbots trên một số hệ thống khác nhau, chúng tôi
có thể đảm bảo rằng ns-3 xây dựng và thực thi đúng cách trên tất cả các hệ thống được hỗ trợ.

Người dùng (và nhà phát triển) thường sẽ không tương tác với hệ thống buildbot ngoài việc
đọc tin nhắn của nó về kết quả kiểm tra. Nếu lỗi được phát hiện ở một trong các
công việc xây dựng và kiểm tra tự động, buildbot sẽ gửi email đến ns-Developers
danh sách gửi thư. Email này sẽ trông giống như

Trong URL chi tiết đầy đủ hiển thị trong email, người ta có thể tìm kiếm từ khóa không
chọn phòng thu âm liên kết cho bước tương ứng để xem lý do thất bại.

Buildbot sẽ thực hiện công việc của mình một cách lặng lẽ nếu không có lỗi và hệ thống sẽ trải qua
chu kỳ xây dựng và kiểm tra mỗi ngày để xác minh rằng tất cả đều ổn.

Test.py
Các buildbot sử dụng chương trình Python, test.py, nó chịu trách nhiệm chạy tất cả các
kiểm tra và thu thập các báo cáo kết quả thành dạng có thể đọc được. Chương trình này là
cũng có sẵn để người dùng và nhà phát triển sử dụng.

test.py rất linh hoạt trong việc cho phép người dùng chỉ định số lượng và loại thử nghiệm để
chạy; cũng như số lượng và loại đầu ra cần tạo ra.

Trước khi chạy test.py, hãy đảm bảo rằng các ví dụ và bài kiểm tra của ns3 đã được xây dựng bằng cách thực hiện
sau đây

$ ./waf config --enable -amples --enable-tests
$ ./waf

Theo mặc định, test.py sẽ chạy tất cả các bài kiểm tra có sẵn và báo cáo lại trạng thái một cách rất ngắn gọn
hình thức. Chạy lệnh

$ ./test.py

sẽ dẫn đến một số PASS, FAIL, TAI NẠN or SKIP các chỉ dẫn theo sau là loại
bài kiểm tra đã được chạy và tên hiển thị của nó.

Waf: Vào thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Rời khỏi thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'xây dựng' đã hoàn thành thành công (0.939 giây)
THẤT ​​BẠI: TestSuite ns3-wifi-propagation-loss-models
ĐẠT: Dịch vụ tên đối tượng TestSuite
ĐẠT: TestSuite pcap-file-object
ĐẠT: TestSuite ns3-tcp-cwnd
...
ĐẠT: Khả năng tương tác TestSuite ns3-tcp
PASS: Ví dụ csma-broadcast
PASS: Ví dụ csma-multicast

Chế độ này nhằm mục đích sử dụng bởi những người dùng quan tâm đến việc xác định xem liệu
phân phối đang hoạt động chính xác và bởi các nhà phát triển quan tâm đến việc xác định xem liệu
những thay đổi họ đã thực hiện đã gây ra bất kỳ sự thoái lui nào.

Có một số tùy chọn có sẵn để kiểm soát hành vi của test.py. Nếu bạn chạy
test.py --Cứu giúp bạn sẽ thấy một bản tóm tắt lệnh như:

Cách sử dụng: test.py [tùy chọn]

Tùy chọn:
-h, --help hiển thị thông báo trợ giúp này và thoát
-b BUILDPATH, --buildpath=BUILDPATH
chỉ định đường dẫn nơi ns-3 được xây dựng (mặc định là
xây dựng thư mục cho biến thể hiện tại)
-c LOẠI, --constrain=LOẠI
hạn chế người chạy thử theo loại thử nghiệm
-e VÍ DỤ, --example=VÍ DỤ
chỉ định một ví dụ duy nhất để chạy (không có đường dẫn tương đối
cần thiết)
-g, --grind chạy các bộ thử nghiệm và ví dụ bằng valgrind
-k, --kinds in các loại bài kiểm tra có sẵn
-l, --list in danh sách các bài kiểm tra đã biết
-m, --multiple báo cáo nhiều lỗi từ bộ thử nghiệm và thử nghiệm
trường hợp
-n, --nowaf không chạy waf trước khi bắt đầu thử nghiệm
-p PYEXAMPLE, --pyexample=PYEXAMPLE
chỉ định một ví dụ python để chạy (với tương đối
đường dẫn)
-r, --retain giữ lại tất cả các tệp tạm thời (thông thường
đã xóa)
-s TEST-SUITE, --suite=TEST-SUITE
chỉ định một bộ thử nghiệm duy nhất để chạy
-t TẬP TIN VĂN BẢN, --text=TẬP TIN VĂN BẢN
ghi kết quả kiểm tra chi tiết vào TEXT-FILE.txt
-v, --verbose in tiến trình và thông báo thông tin
-w HTML-FILE, --web=HTML-FILE, --html=HTML-FILE
ghi kết quả kiểm tra chi tiết vào HTML-FILE.html
-x TẬP TIN XML, --xml=TẬP TIN XML
ghi kết quả kiểm tra chi tiết vào XML-FILE.xml

Nếu chỉ định một kiểu đầu ra tùy chọn, người ta có thể tạo ra các mô tả chi tiết về
kiểm tra và trạng thái. Phong cách có sẵn là văn bảnHTML. Các buildbots sẽ chọn HTML
tùy chọn tạo báo cáo thử nghiệm HTML cho các bản dựng hàng đêm bằng cách sử dụng

$ ./test.py --html=nightly.html

Trong trường hợp này, một tệp HTML có tên ''nightly.html'' sẽ được tạo với một bản tóm tắt đẹp mắt
của thử nghiệm được thực hiện. Định dạng ''người có thể đọc được'' có sẵn cho người dùng quan tâm đến
chi tiết.

$ ./test.py --text=results.txt

Trong ví dụ trên, bộ thử nghiệm đang kiểm tra ns-3 suy hao truyền sóng của thiết bị không dây
các mô hình thất bại Theo mặc định không có thêm thông tin nào được cung cấp.

Để tìm hiểu thêm về sự thất bại, test.py cho phép một bộ thử nghiệm duy nhất được chỉ định.
Chạy lệnh

$ ./test.py --suite=ns3-wifi-propagation-loss-models

hoặc tương đương

$ ./test.py -s ns3-wifi-propagation-loss-models

kết quả là bộ thử nghiệm duy nhất đó đang được chạy.

THẤT ​​BẠI: TestSuite ns3-wifi-propagation-loss-models

Để tìm thông tin chi tiết về lỗi, người ta phải chỉ định loại đầu ra
mong muốn. Ví dụ: hầu hết mọi người có thể sẽ quan tâm đến một tệp văn bản:

$ ./test.py --suite=ns3-wifi-propagation-loss-models --text=results.txt

Điều này sẽ dẫn đến việc bộ thử nghiệm đơn lẻ đó được chạy với trạng thái thử nghiệm được ghi vào
tập tin ''results.txt''.

Bạn sẽ tìm thấy một cái gì đó tương tự như sau trong tập tin đó

THẤT ​​BẠI: Bộ thử nghiệm ''ns3-wifi-propagation-loss-models'' (0.02 người dùng thực 0.01 hệ thống 0.00)
PASS: Test Case "Check ... Friis ... model ..." (thực 0.01 người dùng 0.00 hệ thống 0.00)
THẤT ​​BẠI: Trường hợp thử nghiệm "Kiểm tra ... Mô hình khoảng cách đăng nhập ..." (0.01 người dùng thực 0.01 hệ thống 0.00)
Chi tiết:
Thông báo: Nhận được giá trị SNR không mong muốn
Tình trạng: [mô tả dài về những gì thực sự đã thất bại]
Thực tế: 176.395
Giới hạn: 176.407 +- 0.0005
Tập tin: ../src/test/ns3wifi/propagation-loss-models-test-suite.cc
Đường dây: 360

Lưu ý rằng Bộ thử nghiệm bao gồm hai Trường hợp thử nghiệm. Trường hợp thử nghiệm đầu tiên đã kiểm tra
Mô hình mất lan truyền Friis và đã được thông qua. Trường hợp thử nghiệm thứ hai không kiểm tra được Nhật ký
Mô hình lan truyền khoảng cách. Trong trường hợp này, SNR là 176.395 đã được tìm thấy và thử nghiệm
mong đợi giá trị 176.407 chính xác đến ba chữ số thập phân. Tệp đã triển khai
bài kiểm tra thất bại được liệt kê cũng như dòng mã gây ra lỗi.

Nếu muốn, bạn có thể dễ dàng viết một tệp HTML bằng cách sử dụng --html tùy chọn
như đã mô tả ở trên.

Thông thường người dùng sẽ chạy tất cả các bài kiểm tra ít nhất một lần sau khi tải xuống ns-3 để chắc rằng
môi trường của anh ấy hoặc cô ấy đã được xây dựng chính xác và đang tạo ra kết quả chính xác
theo các bộ thử nghiệm. Các nhà phát triển thường sẽ chạy các bộ thử nghiệm trước và
sau khi thực hiện thay đổi để đảm bảo rằng họ không đưa ra hồi quy với
những thay đổi. Trong trường hợp này, các nhà phát triển có thể không muốn chạy tất cả các thử nghiệm mà chỉ chạy một tập hợp con. Vì
Ví dụ: nhà phát triển có thể chỉ muốn chạy thử nghiệm đơn vị định kỳ trong khi thực hiện
thay đổi đối với một kho lưu trữ. Trong trường hợp này, test.py có thể được yêu cầu hạn chế các loại
các bài kiểm tra đang được chạy cho một lớp kiểm tra cụ thể. Lệnh sau sẽ chỉ dẫn đến
các bài kiểm tra đơn vị đang được chạy:

$ ./test.py --constrain=unit

Tương tự, lệnh sau sẽ chỉ chạy thử nghiệm khói mẫu:

$ ./test.py --constrain=unit

Để xem danh sách nhanh các loại ràng buộc pháp lý, bạn có thể yêu cầu liệt kê chúng.
Lệnh sau

$ ./test.py --kinds

sẽ dẫn đến danh sách sau được hiển thị:

Waf: Vào thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Rời khỏi thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'build' kết thúc thành công (0.939s)Waf: Đang vào thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
bvt: Kiểm tra xác minh bản dựng (để xem bản dựng đã hoàn thành thành công chưa)
core: Chạy tất cả các thử nghiệm dựa trên TestSuite (loại trừ các ví dụ)
ví dụ: Ví dụ (để xem chương trình ví dụ có chạy thành công không)
hiệu suất: Kiểm tra hiệu suất (kiểm tra xem hệ thống có nhanh như mong đợi không)
hệ thống: Kiểm tra hệ thống (mở rộng các mô-đun để kiểm tra sự tích hợp của các mô-đun)
đơn vị: Kiểm tra đơn vị (trong các mô-đun để kiểm tra chức năng cơ bản)

Bất kỳ loại thử nghiệm nào trong số này đều có thể được cung cấp dưới dạng ràng buộc bằng cách sử dụng --hạn chế tùy chọn.

Để xem danh sách nhanh tất cả các bộ thử nghiệm có sẵn, bạn có thể yêu cầu chúng
liệt kê. Lệnh sau,

$ ./test.py --list

sẽ dẫn đến một danh sách bộ thử nghiệm được hiển thị, tương tự như

Waf: Vào thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Rời khỏi thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'xây dựng' đã hoàn thành thành công (0.939 giây)
biểu đồ
nhiễu sóng wifi ns3
ns3-tcp-cwnd
khả năng tương tác ns3-tcp
mẫu
thiết bị-lưới-ngọn lửa
thiết bị-lưới-dot11s
thiết bị-lưới
...
dịch vụ tên đối tượng
gọi lại
thuộc tính
cấu hình
giá trị toàn cầu
dòng lệnh
số cơ bản ngẫu nhiên
vật

Bạn có thể chọn bất kỳ bộ nào được liệt kê để tự chạy bằng cách sử dụng --Thượng hạng tùy chọn như
hiển thị ở trên.

Tương tự như bộ thử nghiệm, người ta có thể chạy một chương trình ví dụ C++ bằng cách sử dụng --thí dụ
lựa chọn. Lưu ý rằng đường dẫn tương đối cho ví dụ không cần phải được đưa vào và rằng
các tệp thực thi được xây dựng cho các ví dụ C++ không có phần mở rộng. Đang vào

$ ./test.py --example=udp-echo

dẫn đến ví dụ duy nhất đó được chạy.

PASS: Ví dụ/udp/udp-echo

Bạn có thể chỉ định thư mục nơi ns-3 được xây dựng bằng cách sử dụng lệnh --đường dẫn xây dựng tùy chọn như
theo sau.

$ ./test.py --buildpath=/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build/debug --example=wifi-simple-adhoc

Người ta có thể chạy một chương trình ví dụ Python bằng cách sử dụng --pyexample Lựa chọn. Lưu ý rằng
phải bao gồm đường dẫn tương đối cho ví dụ và các ví dụ Python cần có chúng
phần mở rộng. Đang vào

$ ./test.py --pyexample=examples/tutorial/first.py

dẫn đến ví dụ duy nhất đó được chạy.

ĐẠT: Ví dụ/tutorial/first.py

Vì các ví dụ Python không được xây dựng nên bạn không cần chỉ định thư mục chứa ns-3
được xây dựng để chạy chúng.

Thông thường khi các chương trình ví dụ được thực thi, chúng ghi một lượng lớn dữ liệu tệp theo dõi.
Điều này thường được lưu vào thư mục cơ sở của bản phân phối (ví dụ:
/home/người dùng/ns-3-dev). Khi test.py chạy một ví dụ, nó thực sự hoàn toàn không quan tâm
với các tập tin theo dõi. Nó chỉ muốn xác định xem ví dụ có thể được xây dựng và chạy hay không
không có lỗi. Vì trường hợp này xảy ra nên các tệp dấu vết được ghi vào một
/tmp/không được kiểm tra-dấu vết danh mục. Nếu bạn chạy ví dụ trên, bạn sẽ có thể tìm thấy
liên quan udp-echo.trudp-echo-n-1.pcap các tập tin ở đó.

Danh sách các ví dụ có sẵn được xác định bởi nội dung của thư mục ''examples'' trong
sự phân phối. Nếu bạn chọn một ví dụ để thực thi bằng cách sử dụng --thí dụ Tùy chọn,
test.py sẽ không cố gắng quyết định xem ví dụ đã được cấu hình hay chưa, nó
sẽ chỉ cố gắng chạy nó và báo cáo kết quả của lần thử.

Thời Gian test.py chạy, theo mặc định, trước tiên nó sẽ đảm bảo rằng hệ thống đã được hoàn tất
được xây dựng. Điều này có thể được khắc phục bằng cách chọn --nowaf tùy chọn.

$ ./test.py --list --nowaf

sẽ dẫn đến một danh sách các bộ thử nghiệm hiện được xây dựng được hiển thị, tương tự như:

ns3-wifi-lan truyền-mất-mô hình
ns3-tcp-cwnd
khả năng tương tác ns3-tcp
đối tượng tập tin pcap
dịch vụ tên đối tượng
máy tạo số ngẫu nhiên

Lưu ý sự vắng mặt của Waf xây dựng thông điệp.

test.py cũng hỗ trợ chạy các bộ thử nghiệm và ví dụ trong valgrind. Valgrind là một
chương trình linh hoạt để gỡ lỗi và định hình các tệp thực thi Linux. Theo mặc định, valgrind chạy
một công cụ tên là memcheck, thực hiện nhiều chức năng kiểm tra bộ nhớ, bao gồm
phát hiện các truy cập vào bộ nhớ chưa được khởi tạo, sử dụng sai bộ nhớ được phân bổ (giải phóng gấp đôi,
truy cập sau khi rảnh, v.v.) và phát hiện rò rỉ bộ nhớ. Điều này có thể được lựa chọn bằng cách sử dụng
--mài ngọc tùy chọn.

$ ./test.py --grind

Khi nó chạy, test.py và các chương trình mà nó chạy gián tiếp, tạo ra số lượng lớn
Hồ sơ tạm thời. Thông thường, nội dung của những tập tin này không thú vị, tuy nhiên trong một số
trường hợp nó có thể hữu ích (cho mục đích gỡ lỗi) để xem các tệp này. test.py cung cấp một
--giữ lại tùy chọn sẽ khiến các tệp tạm thời này được giữ lại sau khi chạy xong.
hoàn thành. Các tập tin được lưu trong thư mục có tên đầu ra thử nghiệm dưới một thư mục con
được đặt tên theo Giờ phối hợp quốc tế hiện tại (còn được gọi là Giờ chuẩn Greenwich
Thời gian).

$ ./test.py --retain

Ngoài ra, thẻ cào test.py cung cấp một --dài dòng tùy chọn sẽ in lượng lớn thông tin
về sự tiến bộ của nó. Người ta không mong đợi rằng điều này sẽ cực kỳ hữu ích trừ khi có
một lỗi. Trong trường hợp này, bạn có thể có quyền truy cập vào đầu ra tiêu chuẩn và lỗi tiêu chuẩn
được báo cáo bằng cách chạy các bộ thử nghiệm và ví dụ. Chọn chi tiết theo cách sau:

$ ./test.py --verbose

Tất cả các tùy chọn này có thể được trộn lẫn và kết hợp. Ví dụ: để chạy tất cả lõi ns-3
bộ thử nghiệm trong valgrind, ở chế độ dài dòng, trong khi tạo tệp đầu ra HTML, một
sẽ làm:

$ ./test.py --verbose --grind --constrain=core --html=results.html

Kiểm traPhân loại
Như đã đề cập ở trên, các bài kiểm tra được nhóm thành một số phân loại được xác định rộng rãi để
cho phép người dùng chạy thử nghiệm có chọn lọc để giải quyết các loại thử nghiệm khác nhau cần
được thực hiện.

· Xây dựng các bài kiểm tra xác minh

· Bài kiểm tra đơn vị

· Kiểm tra hệ thống

· Ví dụ

· Kiểm tra hiệu năng

Kiểm tra xác minh bản dựng
Đây là những thử nghiệm tương đối đơn giản được xây dựng cùng với quá trình phân phối và được sử dụng
để đảm bảo rằng bản dựng hoạt động khá hiệu quả. Các bài kiểm tra đơn vị hiện tại của chúng tôi tồn tại trong
các tệp nguồn của mã mà họ kiểm tra và được tích hợp vào các mô-đun ns-3; và vì vậy phù hợp với
Mô tả của BVT BVT tồn tại trong cùng một mã nguồn được tích hợp trong mã ns-3.
Các bài kiểm tra hiện tại của chúng tôi là ví dụ về loại bài kiểm tra này.

đơn vị Kiểm tra
Kiểm thử đơn vị là các kiểm thử phức tạp hơn, đi sâu vào chi tiết để đảm bảo rằng một đoạn mã
hoạt động như được quảng cáo một cách biệt lập. Thực sự không có lý do gì để loại bài kiểm tra này được thực hiện
được xây dựng trong mô-đun ns-3. Ví dụ, hóa ra đơn vị kiểm tra đối tượng
dịch vụ tên có cùng kích thước với chính mã dịch vụ tên đối tượng. Kiểm tra đơn vị
là các thử nghiệm kiểm tra một bit chức năng không được tích hợp trong mã ns-3,
nhưng nằm trong cùng thư mục với mã mà nó kiểm tra. Có thể những thử nghiệm này
kiểm tra sự tích hợp của nhiều tệp triển khai trong một mô-đun. Tập tin
src/core/test/names-test-suite.cc là một ví dụ về loại thử nghiệm này. Tập tin
src/network/test/pcap-file-test-suite.cc là một ví dụ khác sử dụng pcap tốt đã biết
dưới dạng tệp vectơ thử nghiệm. Tệp này được lưu trữ cục bộ trong thư mục src/network.

WELFARE Kiểm tra
Kiểm tra hệ thống là những kiểm thử liên quan đến nhiều hơn một mô-đun trong hệ thống. Chúng tôi có rất nhiều
loại thử nghiệm này đang chạy trong khung hồi quy hiện tại của chúng tôi, nhưng chúng thường
ví dụ quá tải. Chúng tôi cung cấp một địa điểm mới cho loại thử nghiệm này trong thư mục
src/kiểm tra. Tệp src/test/ns3tcp/ns3-interop-test-suite.cc là một ví dụ về loại này
của bài kiểm tra. Nó sử dụng NSC TCP để kiểm tra việc triển khai TCP ns-3. Thường sẽ có bài kiểm tra
các vectơ cần thiết cho loại thử nghiệm này và chúng được lưu trữ trong thư mục chứa
thử nghiệm cuộc sống. Ví dụ: ns3tcp-interop-response-vectors.pcap là một tệp bao gồm một
số lượng tiêu đề TCP được sử dụng làm phản hồi mong đợi của TCP ns-3 đang được thử nghiệm
đối với kích thích do NSC TCP tạo ra được sử dụng như một triển khai '' hàng hóa đã biết ''.

Các ví dụ
Các ví dụ được kiểm tra theo khung để đảm bảo chúng được xây dựng và sẽ chạy. Không có gì là
đã được kiểm tra và hiện tại các tệp pcap vừa được ghi vào / Tmp bị loại bỏ. Nếu như
các ví dụ chạy (không gặp sự cố) chúng vượt qua bài kiểm tra khói này.

HIỆU QUẢ Kiểm tra
Kiểm thử hiệu năng là những kiểm thử thực hiện một phần cụ thể của hệ thống và xác định
nếu các bài kiểm tra đã được thực hiện để hoàn thành trong một thời gian hợp lý.

Chạy Kiểm tra
Các thử nghiệm thường được chạy bằng cách sử dụng cấp độ cao test.py chương trình. Để có được danh sách các
các tùy chọn dòng lệnh có sẵn, hãy chạy test.py --Cứu giúp

Chương trình thử nghiệm test.py sẽ chạy cả hai bài kiểm tra và những ví dụ đã được thêm vào
danh sách cần kiểm tra. Sự khác biệt giữa các bài kiểm tra và ví dụ như sau. Kiểm tra
thường kiểm tra xem đầu ra hoặc sự kiện mô phỏng cụ thể có phù hợp với hành vi dự kiến ​​hay không.
Ngược lại, đầu ra của các ví dụ không được kiểm tra và chương trình thử nghiệm chỉ kiểm tra
trạng thái thoát của chương trình mẫu để đảm bảo chương trình chạy không có lỗi.

Tóm lại, để chạy tất cả các thử nghiệm, trước tiên người ta phải định cấu hình các thử nghiệm trong giai đoạn cấu hình và
Ngoài ra (tùy chọn) các ví dụ nếu các ví dụ cần được kiểm tra:

$ ./waf --configure --enable-examples --enable-tests

Sau đó, xây dựng ns-3 và sau khi được xây dựng, chỉ cần chạy test.py. test.py -h sẽ hiển thị một số
các tùy chọn cấu hình sửa đổi hoạt động của test.py.

Chương trình test.py gọi, đối với các bài kiểm tra và ví dụ về C++, một chương trình C++ cấp thấp hơn được gọi là
người chạy thử nghiệm để thực sự chạy thử nghiệm. Như được thảo luận dưới đây, điều này người chạy thử nghiệm có thể là một
cách hữu ích để gỡ lỗi các bài kiểm tra.

Gỡ lỗi Kiểm tra
Việc gỡ lỗi các chương trình thử nghiệm được thực hiện tốt nhất khi chạy trình chạy thử nghiệm cấp thấp
chương trình. Người chạy thử nghiệm là cầu nối từ mã Python chung đến ns-3 mã số. Nó là
được viết bằng C++ và sử dụng quy trình khám phá kiểm thử tự động trong ns-3 mã để tìm và
cho phép thực hiện tất cả các thử nghiệm khác nhau.

Lý do chính tại sao test.py không phù hợp để gỡ lỗi vì nó không được phép
đăng nhập để được bật bằng cách sử dụng NS_LOG biến môi trường khi test.py chạy. Cái này
giới hạn không áp dụng cho tệp thực thi của trình chạy thử. Do đó, nếu bạn muốn xem nhật ký
đầu ra từ các thử nghiệm của mình, bạn phải chạy chúng trực tiếp bằng cách sử dụng trình chạy thử.

Để thực thi trình chạy thử, bạn chạy nó giống như bất kỳ tệp thực thi ns-3 nào khác -- sử dụng
WAF. Để có danh sách các tùy chọn có sẵn, bạn có thể gõ:

$ ./waf --run "người chạy thử --help"

Bạn sẽ thấy một cái gì đó như sau

Waf: Vào thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
Waf: Rời khỏi thư mục `/home/craigdo/repos/ns-3-allinone-test/ns-3-dev/build'
'xây dựng' đã hoàn thành thành công (0.353 giây)
--assert: Yêu cầu kiểm tra phân tách (như khẳng định) nếu phát hiện thấy lỗi
--basedir=dir: Đặt thư mục cơ sở (nơi tìm src) thành ''dir''
--tempdir=dir: Đặt thư mục tạm thời (nơi tìm tệp dữ liệu) thành ''dir''
--constrain=test-type: Ràng buộc kiểm tra đối với các bộ thử nghiệm thuộc loại ''test-type''
--help: In thông báo này
--kinds: Liệt kê tất cả các loại bài kiểm tra có sẵn
--list: Liệt kê tất cả các bộ thử nghiệm (tùy chọn bị ràng buộc bởi loại thử nghiệm)
--out=file-name: Đặt tệp đầu ra trạng thái kiểm tra thành ''tên tệp''
--suite=suite-name: Chạy bộ thử nghiệm có tên ''suite-name''
--verbose: Bật tin nhắn trong bộ thử nghiệm chạy

Có một số thứ có sẵn cho bạn và sẽ quen thuộc với bạn nếu bạn có
nhìn test.py. Điều này có thể đoán trước được vì trình chạy thử chỉ là một giao diện
giữa test.pyns-3. Bạn có thể nhận thấy rằng các lệnh liên quan đến ví dụ bị thiếu ở đây.
Đó là bởi vì các ví dụ thực sự không ns-3 kiểm tra. test.py điều hành chúng như thể chúng là
để trình bày một môi trường thử nghiệm thống nhất, nhưng chúng thực sự hoàn toàn khác nhau và không
được tìm thấy ở đây.

Tùy chọn mới đầu tiên xuất hiện ở đây, nhưng không có trong test.py là --khẳng định Lựa chọn. Điều này
tùy chọn này rất hữu ích khi gỡ lỗi một trường hợp thử nghiệm khi chạy trong trình gỡ lỗi như gdb. Khi nào
được chọn, tùy chọn này sẽ báo cho trường hợp kiểm thử cơ bản gây ra vi phạm phân đoạn nếu
một lỗi được phát hiện. Điều này có tác dụng phụ là khiến việc thực thi chương trình bị dừng lại
(đột nhập vào trình gỡ lỗi) khi phát hiện ra lỗi. Nếu bạn đang sử dụng gdb, bạn có thể sử dụng
tùy chọn này giống như,

$ ./vỏ waf
$ cd xây dựng/gỡ lỗi/utils
Người chạy thử nghiệm $ gdb
$ run --suite=giá trị toàn cầu --assert

Nếu tìm thấy lỗi trong bộ kiểm tra giá trị toàn cầu, một lỗi phân tách sẽ được tạo
và trình gỡ lỗi (cấp nguồn) sẽ dừng ở NS_TEST_ASSERT_MSG đã phát hiện ra
lỗi.

Một tùy chọn mới khác xuất hiện ở đây là --basedir lựa chọn. Hoá ra là một số
kiểm tra có thể cần phải tham khảo thư mục nguồn của ns-3 phân phối để tìm địa phương
data, vì vậy luôn cần có một thư mục cơ sở để chạy thử nghiệm.

Nếu bạn chạy thử nghiệm từ test.py, chương trình Python sẽ cung cấp tùy chọn dựa trên
Bạn. Để chạy một trong các thử nghiệm trực tiếp từ người chạy thử bằng cách sử dụng WAF, bạn sẽ cần đến
chỉ định bộ thử nghiệm để chạy cùng với thư mục cơ sở. Vì vậy bạn có thể sử dụng shell
và làm:

$ ./waf --run "test-runner --basedir=`pwd` --suite=pcap-file-object"

Lưu ý dấu ngoặc kép ''ngược lại'' trên pwd chỉ huy.

Nếu bạn đang chạy bộ thử nghiệm từ trình gỡ lỗi, việc ghi nhớ có thể khá khó khăn
và liên tục gõ đường dẫn tuyệt đối của thư mục cơ sở phân phối. Bởi vì
điều này, nếu bạn bỏ qua cơ sở, người chạy thử sẽ cố gắng tìm ra cơ sở cho bạn. Nó
bắt đầu trong thư mục làm việc hiện tại và đi lên cây thư mục để tìm kiếm
tập tin thư mục với các tập tin có tên PHIÊN BẢNGIẤY PHÉP. Nếu nó tìm thấy một cái, nó cho rằng
phải là cơ sở của họ và cung cấp nó cho bạn.

Thử nghiệm đầu ra
Nhiều bộ thử nghiệm cần ghi các tệp tạm thời (chẳng hạn như tệp pcap) trong quá trình
chạy thử nghiệm. Các bài kiểm tra sau đó cần một thư mục tạm thời để ghi vào. con trăn
tiện ích kiểm tra (test.py) sẽ tự động cung cấp một tệp tạm thời, nhưng nếu chạy độc lập
thư mục tạm thời này phải được cung cấp. Cũng giống như trong trường hợp của họ, nó có thể
khó chịu khi liên tục phải cung cấp một --tempdir, do đó người chạy thử sẽ tìm ra một
dành cho bạn nếu bạn không cung cấp. Đầu tiên nó tìm kiếm các biến môi trường có tên TMP
TEMP và sử dụng những thứ đó. Nếu không TMP cũng không TEMP được xác định nó chọn / Tmp. Mật mã
sau đó gắn vào một mã định danh cho biết cái gì đã tạo ra thư mục (ns-3) rồi thời gian
(hh.mm.ss) theo sau là một số lượng lớn ngẫu nhiên. Người chạy thử tạo một thư mục đó
tên được sử dụng làm thư mục tạm thời. Các tập tin tạm thời sau đó đi vào một thư mục
sẽ được đặt tên giống như

/tmp/ns-3.10.25.37.61537845

Thời gian được cung cấp như một gợi ý để bạn có thể dễ dàng xây dựng lại những gì
thư mục đã được sử dụng nếu bạn cần quay lại và xem các tập tin được đặt trong đó
thư mục.

Một loại đầu ra khác là đầu ra thử nghiệm như dấu vết pcap được tạo ra để so sánh với
đầu ra tham chiếu. Chương trình thử nghiệm thường sẽ xóa những thứ này sau khi bộ thử nghiệm hoàn tất.
chạy. Để tắt tính năng xóa đầu ra kiểm tra, hãy chạy test.py với tùy chọn "giữ lại":

$ ./test.py -r

và đầu ra thử nghiệm có thể được tìm thấy trong testpy-output/ thư mục.

Báo cáo of thử nghiệm thất bại
Theo mặc định, khi bạn chạy một bộ thử nghiệm bằng trình chạy thử, nó sẽ chạy thử nghiệm một cách lặng lẽ.
Dấu hiệu duy nhất cho thấy bạn sẽ đạt được kết quả bài kiểm tra là vắng mặt của một tin nhắn
từ WAF nói rằng chương trình trả về một cái gì đó không phải là mã thoát bằng 0. Để có được
một số đầu ra từ thử nghiệm, bạn cần chỉ định một tệp đầu ra mà thử nghiệm sẽ
viết trạng thái XML của họ bằng cách sử dụng --ngoài lựa chọn. Bạn cần phải cẩn thận khi diễn giải các
kết quả vì bộ thử nghiệm sẽ thêm kết quả vào tập tin này. Thử,

$ ./waf --run "test-runner --basedir=`pwd` --suite=pcap-file-object --out=myfile.xml"

Nếu bạn nhìn vào tập tin myfile.xml bạn sẽ thấy một cái gì đó như,


đối tượng tập tin pcap

Kiểm tra xem PcapFile::Open with mode ''w'' có hoạt động không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Kiểm tra xem PcapFile::Open with mode ''r'' có hoạt động không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Kiểm tra xem PcapFile::Open with mode ''a'' có hoạt động không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Kiểm tra xem PcapFileHeader có được quản lý chính xác không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Kiểm tra xem PcapRecordHeader có được quản lý chính xác không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Kiểm tra xem PcapFile có thể đọc được tệp pcap tốt đã biết không
VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00

VƯỢT QUA
thực 0.00 người dùng 0.00 hệ thống 0.00


Nếu bạn quen thuộc với XML thì điều này khá dễ hiểu. Nó cũng không phải là một
tệp XML hoàn chỉnh vì các bộ thử nghiệm được thiết kế để gắn đầu ra của chúng vào tệp chính
Tệp trạng thái XML như được mô tả trong test.py phần.

Gỡ lỗi thử nghiệm bộ thất bại
Để gỡ lỗi các sự cố kiểm tra, chẳng hạn như

SỰ CỐ: TestSuite ns3-nhiễu-wifi

Bạn có thể truy cập chương trình chạy thử cơ bản thông qua gdb như sau, sau đó chuyển
Đối số "--basedir=`pwd`" để chạy (bạn cũng có thể chuyển các đối số khác nếu cần, nhưng
dựa trên là mức tối thiểu cần thiết):

$ ./waf --command-template="gdb %s" --run "người chạy thử"
Waf: Vào thư mục `/home/tomh/hg/sep09/ns-3-allinone/ns-3-dev-678/build'
Waf: Rời khỏi thư mục `/home/tomh/hg/sep09/ns-3-allinone/ns-3-dev-678/build'
'xây dựng' đã hoàn thành thành công (0.380 giây)
GNU gdb 6.8-debian
Bản quyền (C) 2008 Free Software Foundation, Inc.
L Hương GPLv3+: GNU GPL phiên bản 3 trở lênhttp://gnu.org/licenses/gpl.html>
Đây là phần mềm miễn phí: bạn có thể tự do thay đổi và phân phối lại nó.
KHÔNG CÓ BẢO ĐẢM, trong phạm vi pháp luật cho phép. Nhập "hiển thị sao chép"
và "hiển thị bảo hành" để biết chi tiết.
GDB này được định cấu hình là "x86_64-linux-gnu"...
(gdb) r --basedir=`pwd`
Chương trình đang bắt đầu: <..>/build/debug/utils/test-runner --basedir=`pwd`
[Gỡ lỗi luồng bằng cách sử dụng libthread_db đã bật]
Khẳng định thất bại. file=../src/core/model/type-id.cc, line=138, cond="uid <= m_information.size () && uid != 0"
...

Đây là một ví dụ khác về cách sử dụng valgrind để gỡ lỗi vấn đề bộ nhớ, chẳng hạn như:

VALGR: TestSuite thiết bị-lưới-dot11s-hồi quy

$ ./waf --command-template="valgrind %s --basedir=`pwd` --suite=devices-mesh-dot11s-regression" --run test-runner

Lớp Người chạy thử nghiệm
Các tệp thực thi chạy các chương trình thử nghiệm chuyên dụng sử dụng lớp TestRunner. Lớp học này
cung cấp khả năng đăng ký và liệt kê bài kiểm tra tự động, cũng như cách thức thực hiện
các bài kiểm tra cá nhân. Các bộ thử nghiệm riêng lẻ sử dụng các hàm tạo toàn cục của C++ để tự thêm chúng vào
một tập hợp các bộ thử nghiệm được quản lý bởi người chạy thử. Người chạy thử nghiệm được sử dụng để liệt kê
tất cả các bài kiểm tra có sẵn và chọn một bài kiểm tra để chạy. Đây là một lớp học khá đơn giản
cung cấp ba phương thức tĩnh để cung cấp hoặc Thêm và Lấy các bộ thử nghiệm vào một
tập hợp các bài kiểm tra. Xem doxygen cho lớp học ns3::TestRunner để biết thêm chi tiết.

Thử nghiệm Suite
Tất cả ns-3 các bài kiểm thử được phân loại thành Bộ kiểm thử và Trường hợp kiểm thử. Một bộ thử nghiệm là một
tập hợp các ca kiểm thử thực hiện đầy đủ một loại chức năng nhất định. BẰNG
được mô tả ở trên, các bộ thử nghiệm có thể được phân loại là,

· Xây dựng các bài kiểm tra xác minh

· Bài kiểm tra đơn vị

· Kiểm tra hệ thống

· Ví dụ

· Kiểm tra hiệu năng

Phân loại này được xuất từ ​​lớp TestSuite. Lớp này khá đơn giản,
chỉ tồn tại như một nơi để xuất loại này và tích lũy các trường hợp thử nghiệm. Từ một người dùng
phối cảnh, để tạo TestSuite mới trong hệ thống, người ta chỉ phải xác định một TestSuite mới
lớp kế thừa từ lớp TestSuite và thực hiện hai nhiệm vụ này.

Đoạn mã sau sẽ định nghĩa một lớp mới có thể được điều hành bởi test.py dưới dạng bài kiểm tra ''đơn vị''
với tên hiển thị, tên-test-suite của tôi.

lớp MySuite : TestSuite công khai
{
công khai:
MyTestSuite();
};

MyTestSuite::MyTestSuite ()
: TestSuite ("my-test-suite-name", UNIT)
{
AddTestCase (MyTestCase mới);
}

MyTestSuite myTestSuite;

Lớp cơ sở đảm nhiệm tất cả việc đăng ký và báo cáo cần thiết để hoạt động tốt
công dân trong khuôn khổ kiểm tra.

Thử nghiệm Khay
Các thử nghiệm riêng lẻ được tạo bằng lớp TestCase. Các mô hình phổ biến để sử dụng bài kiểm tra
trường hợp bao gồm "một trường hợp thử nghiệm cho mỗi tính năng" và "một trường hợp thử nghiệm cho mỗi phương thức". Hỗn hợp của
những mô hình này có thể được sử dụng.

Để tạo một ca kiểm thử mới trong hệ thống, tất cả những gì người ta phải làm là kế thừa từ
Trường hợp thử nghiệm lớp cơ sở, ghi đè hàm tạo để đặt tên cho trường hợp kiểm thử và ghi đè
các DoRun phương pháp để chạy thử nghiệm.

lớp MyTestCase : TestCase công khai
{
MyTestCase();
khoảng trống ảo DoRun (void);
};

MyTestCase::MyTestCase ()
: TestCase ("Kiểm tra một số chức năng")
{
}

làm mất hiệu lực
MyTestCase::DoRun (void)
{
NS_TEST_ASSERT_MSG_EQ (đúng, đúng, "Một số thông báo lỗi");
}

Tiện ích
Có một số loại tiện ích khác nhau cũng là một phần của thử nghiệm
khuôn khổ. Các ví dụ bao gồm tệp pcap tổng quát hữu ích để lưu trữ vectơ kiểm tra; Một
vùng chứa chung hữu ích cho việc lưu trữ tạm thời các vectơ kiểm tra trong quá trình thực hiện kiểm tra; Và
công cụ để tạo bản trình bày dựa trên kết quả kiểm tra xác nhận và xác minh.

Những tiện ích này không được ghi lại ở đây, nhưng ví dụ, vui lòng xem cách kiểm tra TCP
tìm thấy trong src/test/ns3tcp/ sử dụng tập tin pcap và đầu ra tham chiếu.

Làm thế nào đến viết kiểm tra
Mục tiêu chính của dự án ns-3 là giúp người dùng nâng cao tính hợp lệ và
độ tin cậy của kết quả của họ. Có nhiều yếu tố để có được các mô hình hợp lệ và
mô phỏng và thử nghiệm là thành phần chính. Nếu bạn đóng góp mô hình hoặc ví dụ cho
ns-3, bạn có thể được yêu cầu đóng góp mã kiểm tra. Các mô hình mà bạn đóng góp sẽ được sử dụng
trong nhiều năm bởi những người khác, những người có thể không biết ngay từ cái nhìn đầu tiên liệu
mô hình là đúng. Mã kiểm tra mà bạn viết cho mô hình của mình sẽ giúp tránh những rủi ro trong tương lai.
hồi quy ở đầu ra và sẽ hỗ trợ người dùng trong tương lai hiểu được việc xác minh và
giới hạn khả năng áp dụng của mô hình của bạn.

Có nhiều cách để xác minh tính đúng đắn của việc triển khai mô hình. Trong này
phần này, chúng tôi hy vọng sẽ đề cập đến một số trường hợp phổ biến có thể được sử dụng làm hướng dẫn cách viết mới.
kiểm tra.

Mâu TestSuite bộ xương
Khi bắt đầu từ đầu (tức là không thêm TestCase vào TestSuite hiện có), những điều này
mọi việc cần phải được quyết định trước:

· Bộ thử nghiệm sẽ được gọi là gì

· Loại thử nghiệm đó sẽ là gì (Thử nghiệm xác minh bản dựng, Thử nghiệm đơn vị, Thử nghiệm hệ thống hoặc
Kiểm tra hiệu suất)

· Nơi mã kiểm tra sẽ tồn tại (trong mô-đun ns-3 hiện có hoặc riêng biệt trong
thư mục src/test/). Bạn sẽ phải chỉnh sửa tệp wscript trong thư mục đó để
biên dịch mã mới của bạn, nếu đó là một tệp mới.

Một chương trình được gọi là src/create-module.py là một điểm khởi đầu tốt Chương trình này có thể được
được gọi như tạo-module.py Router cho một mô-đun mới giả định được gọi là Router. Một lần
bạn làm điều này, bạn sẽ thấy một Router thư mục và một kiểm tra/router-test-suite.cc bộ thử nghiệm.
Tệp này có thể là điểm khởi đầu cho thử nghiệm đầu tiên của bạn. Đây là một bộ thử nghiệm hoạt động,
mặc dù các thử nghiệm thực tế được thực hiện là tầm thường. Sao chép nó vào bài kiểm tra mô-đun của bạn
thư mục và thực hiện thay thế toàn cục "Bộ định tuyến" trong tệp đó cho nội dung nào đó liên quan
vào mô hình mà bạn muốn thử nghiệm. Bạn cũng có thể chỉnh sửa những thứ như mô tả chi tiết hơn
tên ca kiểm thử.

Bạn cũng cần thêm một khối vào wscript của mình để biên dịch bài kiểm tra này:

module_test.source = [
'kiểm tra/bộ định tuyến-test-suite.cc',
]

Trước khi bạn thực sự bắt đầu thực hiện những việc hữu ích này, bạn có thể thử chạy
bộ xương. Đảm bảo rằng ns-3 đã được cấu hình với tùy chọn "--enable-tests".
Giả sử rằng bộ thử nghiệm mới của bạn được gọi là "bộ định tuyến", chẳng hạn như ở đây:

RouterTestSuite::RouterTestSuite ()
: TestSuite ("bộ định tuyến", ĐƠN VỊ)

Hãy thử lệnh này:

$ ./test.py -s bộ định tuyến

Đầu ra như dưới đây sẽ được tạo ra:

ĐẠT: Bộ định tuyến TestSuite
1 trong 1 bài kiểm tra đã đạt (1 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Xem src/lte/test/test-lte-antenna.cc để biết ví dụ hoạt động.

Thử nghiệm macro
Có một số macro có sẵn để kiểm tra đầu ra của chương trình thử nghiệm với dự kiến
đầu ra. Các macro này được xác định trong src/core/model/test.h.

Nhóm macro chính được sử dụng bao gồm:

NS_TEST_ASSERT_MSG_EQ(thực tế, giới hạn, tin nhắn)
NS_TEST_ASSERT_MSG_NE(thực tế, giới hạn, tin nhắn)
NS_TEST_ASSERT_MSG_LT(thực tế, giới hạn, tin nhắn)
NS_TEST_ASSERT_MSG_GT(thực tế, giới hạn, tin nhắn)
NS_TEST_ASSERT_MSG_EQ_TOL(thực tế, giới hạn, tol, tin nhắn)

Đối số đầu tiên thực tế là giá trị được kiểm tra, giá trị thứ hai hạn chế là điều được mong đợi
giá trị (hoặc giá trị để kiểm tra) và đối số cuối cùng msg là thông báo lỗi tới
in ra nếu kiểm tra thất bại.

Bốn macro đầu tiên ở trên kiểm tra sự bằng nhau, bất bình đẳng, nhỏ hơn hoặc lớn hơn,
tương ứng. Macro thứ năm ở trên kiểm tra sự bình đẳng nhưng trong một phạm vi cho phép nhất định.
Biến thể này hữu ích khi kiểm tra sự bằng nhau của các số dấu phẩy động so với giới hạn,
nơi bạn muốn tránh lỗi kiểm tra do lỗi làm tròn.

Cuối cùng, có các biến thể ở trên trong đó từ khóa XÁC NHẬN được thay thế bởi CHỜ ĐỢI.
Các biến thể này được thiết kế đặc biệt để sử dụng trong các phương thức (đặc biệt là gọi lại) trả về
trống rỗng. Bảo lưu việc sử dụng chúng cho các cuộc gọi lại mà bạn sử dụng trong các chương trình thử nghiệm của mình; nếu không, hãy sử dụng
các XÁC NHẬN biến thể.

Làm thế nào đến thêm vào an ví dụ chương trình đến các thử nghiệm bộ
Người ta có thể "thử khói" các ví dụ biên dịch và chạy thành công cho đến khi hoàn thành (không cần
rò rỉ bộ nhớ) bằng cách sử dụng ví dụ-to-run.py tập lệnh nằm trong thư mục kiểm tra mô-đun của bạn.
Tóm lại, bằng cách đưa một phiên bản của tệp này vào thư mục kiểm tra của bạn, bạn có thể gây ra lỗi
người chạy thử để thực hiện các ví dụ được liệt kê. Thông thường tốt nhất là đảm bảo rằng bạn
chọn các ví dụ có thời gian chạy ngắn hợp lý để không làm hỏng bài kiểm tra. Nhìn thấy
ví dụ trong src/lte/kiểm tra/ thư mục.

Kiểm tra cho boolean kết quả
Kiểm tra kết quả khi nào ngẫu nhiên is tham gia
Kiểm tra đầu ra dữ liệu chống lại a nổi tiếng phân phối
Cung cấp không tầm thường đầu vào vectơ of dữ liệu
Lưu trữ tham khảo không tầm thường đầu ra dữ liệu
Trình bày qua một vài thao tác đơn giản về đầu ra thử nghiệm dữ liệu
cá nhân hóa
Tạo a người mới ns-3 kiểu mẫu
Chương này trình bày quá trình thiết kế một ns-3 người mẫu. Trong nhiều trường hợp nghiên cứu,
người dùng sẽ không hài lòng khi chỉ điều chỉnh các mô hình hiện có mà có thể muốn mở rộng
cốt lõi của trình mô phỏng theo một cách mới lạ. Chúng ta sẽ sử dụng ví dụ về việc thêm ErrorModel vào một
đơn giản ns-3 liên kết như một ví dụ thúc đẩy về cách người ta có thể tiếp cận vấn đề này và
tiến hành thông qua thiết kế và thực hiện.

LƯU Ý:
Tài liệu

Ở đây chúng tôi tập trung vào quá trình tạo mô hình mới và mô-đun mới cũng như một số
lựa chọn thiết kế liên quan. Để rõ ràng, chúng tôi trì hoãn việc thảo luận về cơ khí
tài liệu hóa các mô hình và mã nguồn cho Tài liệu chương.

Thiết kế Phương pháp tiếp cận
Hãy cân nhắc xem bạn muốn nó hoạt động như thế nào; nó nên làm gì. Hãy suy nghĩ về những điều này:

· chức năng: Nó nên có chức năng gì? Thuộc tính hoặc cấu hình là gì
tiếp xúc với người dùng?

· khả năng sử dụng lại: Những người khác có thể sử dụng lại thiết kế của tôi ở mức độ nào? Tôi có thể sử dụng lại mã từ
ns-2 để bắt đầu? Làm thế nào để người dùng tích hợp mô hình với phần còn lại của người khác
mô phỏng?

· phụ thuộc: Làm cách nào tôi có thể giảm bớt việc đưa các phụ thuộc bên ngoài vào mã mới của mình
càng nhiều càng tốt (để làm cho nó có tính mô-đun hơn)? Ví dụ, tôi có nên tránh bất kỳ
phụ thuộc vào IPv4 nếu tôi muốn nó cũng được sử dụng bởi IPv6? Tôi có nên tránh mọi sự phụ thuộc
trên IP chút nào?

Đừng ngần ngại liên hệ với ns-3-người dùng or ns-Developers liệt kê nếu bạn có thắc mắc.
Đặc biệt, điều quan trọng là phải suy nghĩ về API công khai của mô hình mới của bạn và yêu cầu
nhận xét. Nó cũng giúp cho người khác biết về công việc của bạn trong trường hợp bạn quan tâm
cộng tác viên.

Ví dụ: Mô hình lỗi
Một mô hình lỗi tồn tại trong ns-2. Nó cho phép các gói được chuyển đến một đối tượng có trạng thái
xác định, dựa trên một biến ngẫu nhiên, liệu gói tin có bị hỏng hay không. Người gọi có thể
sau đó quyết định phải làm gì với gói tin (bỏ nó đi, v.v.).

API chính của mô hình lỗi là chức năng truyền gói tin tới và giá trị trả về của
hàm này là một boolean cho người gọi biết liệu có bất kỳ lỗi nào xảy ra hay không. Ghi chú
tùy thuộc vào mô hình lỗi, bộ đệm dữ liệu gói có thể bị hỏng hoặc không.
Hãy gọi hàm này là "IsCorrupt()".

Cho đến nay, trong thiết kế của chúng tôi, chúng tôi có:

lớp ErrorModel
{
công khai:
/ **
* \trả về true nếu Gói được coi là bị lỗi/hỏng
* Gói \param pkt để áp dụng mô hình lỗi cho
*/
bool IsCorrupt (Ptr gói);
};

Lưu ý rằng chúng ta không truyền con trỏ hằng, do đó cho phép hàm sửa đổi
gói nếu IsCorrupt() trả về true. Không phải tất cả các mô hình lỗi đều thực sự sửa đổi gói tin;
liệu bộ đệm dữ liệu gói có bị hỏng hay không cần được ghi lại.

Chúng tôi cũng có thể muốn có các phiên bản chuyên biệt về điều này, chẳng hạn như trong ns-2, vì vậy mặc dù nó không phải là
lựa chọn thiết kế duy nhất cho tính đa hình, chúng tôi giả định rằng chúng tôi sẽ phân lớp một lớp cơ sở
ErrorModel dành cho các lớp chuyên biệt, chẳng hạn như RateErrorModel, ListErrorModel, v.v., chẳng hạn như
được thực hiện trong ns-2.

Tại thời điểm này, bạn có thể đang nghĩ: "Tại sao không biến IsCorrupt() thành một phương thức ảo?". Đó là
Một cách tiếp cận; cách khác là làm cho chức năng phi ảo công khai trở nên gián tiếp thông qua một
hàm ảo riêng tư (điều này trong C++ được gọi là thành ngữ giao diện không ảo và được
được thông qua trong ns-3 Lớp ErrorModel).

Tiếp theo, thiết bị này có phụ thuộc vào IP hoặc các giao thức khác không? Chúng tôi không muốn
để tạo sự phụ thuộc vào các giao thức Internet (mô hình lỗi phải được áp dụng cho
các giao thức không phải Internet), vì vậy chúng ta sẽ ghi nhớ điều đó sau.

Một vấn đề cần cân nhắc khác là cách các đối tượng sẽ bao gồm mô hình lỗi này. Chúng tôi hình dung việc đưa
ví dụ: một trình thiết lập rõ ràng trong một số triển khai NetDevice nhất định.:

/ **
* Đính kèm ErrorModel nhận vào PointToPointNetDevice.
*
* PointToPointNetDevice có thể tùy chọn bao gồm ErrorModel trong
* chuỗi nhận gói.
*
* @xem ErrorModel
* @param em Ptr tới ErrorModel.
*/
void PointToPointNetDevice::SetReceiveErrorModel(Ptr em);

Một lần nữa, đây không phải là lựa chọn duy nhất mà chúng ta có (các mô hình lỗi có thể được tổng hợp thành nhiều
các đối tượng khác), nhưng nó đáp ứng trường hợp sử dụng chính của chúng tôi, đó là cho phép người dùng buộc
lỗi về việc truyền gói thành công ở cấp độ NetDevice.

Sau một hồi suy nghĩ và nhìn vào hiện tại ns-2 mã, đây là API mẫu của cơ sở
lớp và lớp con đầu tiên có thể được đăng để xem xét ban đầu:

lớp ErrorModel
{
công khai:
ErrorModel ();
ảo ~ErrorModel ();
bool IsCorrupt (Ptr gói);
đặt lại khoảng trống (void);
void Kích hoạt (void);
void Vô hiệu hóa (void);
bool IsEnabled (void) const;
riêng tư:
bool ảo DoCorrupt (Ptr pkt) = 0;
khoảng trống ảo DoReset (void) = 0;
};

đơn vị lỗi enum
{
EU_BIT,
EU_BYTE,
EU_PKT
};

// Xác định gói nào bị lỗi tương ứng với gói cơ bản
// phân phối biến ngẫu nhiên, tỷ lệ lỗi và đơn vị cho tỷ lệ.
lớp RateErrorModel : ErrorModel công khai
{
công khai:
RateErrorModel ();
ảo ~RateErrorModel ();
enum ErrorUnit GetUnit (void) const;
void SetUnit (enum ErrorUnit error_unit);
nhân đôi GetRate (void) const;
void SetRate (tỷ lệ gấp đôi);
void SetRandomVariable (const RandomVariable &ranvar);
riêng tư:
bool ảo DoCorrupt (Ptr gói);
khoảng trống ảo DoReset (void);
};

Đoạn đầu đài
Giả sử bạn đã sẵn sàng bắt đầu triển khai; bạn có một bức tranh khá rõ ràng về
những gì bạn muốn xây dựng và bạn có thể đã trưng cầu một số đánh giá hoặc đề xuất ban đầu từ
danh sách. Một cách để tiếp cận bước tiếp theo (triển khai) là tạo giàn giáo và
điền vào các chi tiết khi thiết kế hoàn thiện.

Phần này trình bày nhiều bước bạn nên xem xét để xác định giàn giáo, hoặc
một bộ khung phi chức năng về những gì mô hình của bạn cuối cùng sẽ triển khai. Nó thường tốt
hãy luyện tập để không chờ đợi những chi tiết này được tích hợp vào cuối mà thay vào đó hãy tìm hiểu kỹ
khung mô hình của bạn vào hệ thống sớm và sau đó thêm các chức năng sau khi API và
hội nhập có vẻ đúng.

Lưu ý rằng bạn sẽ muốn sửa đổi một số điều trong phần trình bày bên dưới cho mô hình của mình
vì nếu bạn làm theo nguyên văn mô hình lỗi, mã bạn tạo ra sẽ xung đột với
mô hình lỗi hiện có. Dưới đây chỉ là bản phác thảo về cách ErrorModel được xây dựng mà bạn
có thể thích ứng với các mô hình khác.

Phê duyệt các ns-3 Lập trình Phong cách Tài liệu
Tại thời điểm này, bạn có thể muốn tạm dừng và đọc ns-3 tài liệu phong cách mã hóa, đặc biệt là
nếu bạn đang cân nhắc việc đóng góp mã của mình cho dự án. Phong cách mã hóa
tài liệu được liên kết ra khỏi trang dự án chính: ns-3 mã hóa phong cách.

Quyết định Ở đâu in các nguồn Cây các Mẫu Nếu Cư trú tại
Tất cả các ns-3 mã nguồn mô hình nằm trong thư mục src /. Bạn sẽ cần phải chọn cái nào
thư mục con mà nó nằm trong đó. Nếu đó là mã mô hình mới thuộc loại nào đó, thì nên đặt nó
vào src / thư mục ở đâu đó, đặc biệt là để dễ tích hợp với bản dựng
hệ thống.

Trong trường hợp mô hình lỗi, nó liên quan rất nhiều đến lớp gói, vì vậy nó có ý nghĩa
để thực hiện điều này trong src/mạng/ mô-đun ở đâu ns-3 các gói được thực hiện.

WAF chữ viết
ns-3 sử dụng Waf xây dựng hệ thống. Bạn sẽ muốn tích hợp cái mới của bạn ns-3 sử dụng Waf
xây dựng hệ thống. Bạn sẽ muốn tích hợp các tệp nguồn mới của mình vào hệ thống này. Cái này
yêu cầu bạn thêm các tập tin của bạn vào chữ viết tập tin được tìm thấy trong mỗi thư mục.

Hãy bắt đầu với các tệp trống error-model.h và error-model.cc, rồi thêm tệp này vào
src/mạng/wscript. Nó thực sự chỉ là vấn đề thêm tệp .cc vào phần còn lại của
tệp nguồn và tệp .h vào danh sách các tệp tiêu đề.

Bây giờ, hãy mở thư mục cấp cao nhất và gõ "./test.py". Đáng lẽ bạn không nên làm hỏng
bất cứ điều gì bằng hoạt động này.

Bao gồm Lính canh
Tiếp theo, hãy thêm một số bao gồm bảo vệ trong tệp tiêu đề của chúng tôi.:

#ifndef ERROR_MODEL_H
#define ERROR_MODEL_H
...
#endif

không gian tên Ns3
ns-3 sử dụng ns-3 không gian tên để tách biệt các ký hiệu của nó khỏi các không gian tên khác. Thông thường, một
người dùng tiếp theo sẽ đặt một ns-3 khối không gian tên trong cả tệp cc và h.:

không gian tên ns3 {
...
}

Tại thời điểm này, chúng ta có một số tệp khung trong đó chúng ta có thể bắt đầu xác định các lớp mới của mình.
Tệp tiêu đề trông như thế này:

#ifndef ERROR_MODEL_H
#define ERROR_MODEL_H

không gian tên ns3 {

} // không gian tên ns3
#endif

trong khi lỗi-model.cc tập tin chỉ trông như thế này:

#include "error-model.h"

không gian tên ns3 {

} // không gian tên ns3

Các tệp này sẽ được biên dịch vì chúng thực sự không có bất kỳ nội dung nào. Bây giờ chúng tôi đã sẵn sàng để
bắt đầu thêm lớp học.

Ban đầu Triển khai hệ thống
Tại thời điểm này, chúng ta vẫn đang làm việc trên một số giàn giáo, nhưng chúng ta có thể bắt đầu xác định
các lớp, với chức năng sẽ được thêm vào sau.

Thừa kế từ các Đối tượng Lớp?
Đây là bước thiết kế quan trọng; có nên sử dụng lớp không Đối tượng như một lớp cơ sở cho cái mới của bạn
các lớp học.

Như đã mô tả ở chương ns-3 Mô hình đối tượng, các lớp kế thừa từ lớp
Đối tượng có được tính chất đặc biệt:

· NS ns-3 hệ thống loại và thuộc tính (xem Thuộc tính)

· một hệ thống tập hợp đối tượng

· hệ thống đếm tham chiếu con trỏ thông minh (lớp Ptr)

Các lớp bắt nguồn từ lớp Cơ sở đối tượng} lấy hai thuộc tính đầu tiên ở trên, nhưng không
có được con trỏ thông minh. Các lớp bắt nguồn từ lớp Cơ sở đếm số lượt giới thiệu chỉ lấy con trỏ thông minh
hệ thống đếm tham chiếu

Trong thực tế, lớp Đối tượng là biến thể của ba điều trên mà ns-3 nhà phát triển sẽ
thường gặp nhất.

Trong trường hợp của chúng tôi, chúng tôi muốn sử dụng hệ thống thuộc tính và chúng tôi sẽ chuyển các phiên bản
của đối tượng này trên khắp ns-3 API công khai, vì vậy lớp Đối tượng là phù hợp với chúng tôi.

Ban đầu Các lớp học
Một cách để tiến hành là bắt đầu bằng việc xác định các hàm tối thiểu và xem liệu chúng có phù hợp hay không.
biên dịch. Hãy xem lại tất cả những gì cần thực hiện khi chúng ta bắt nguồn từ lớp Object.:

#ifndef ERROR_MODEL_H
#define ERROR_MODEL_H

#include "ns3 / object.h"

không gian tên ns3 {

lớp ErrorModel : đối tượng công cộng
{
công khai:
TypeId tĩnh GetTypeId (void);

ErrorModel ();
ảo ~ErrorModel ();
};

lớp RateErrorModel : ErrorModel công khai
{
công khai:
TypeId tĩnh GetTypeId (void);

RateErrorModel ();
ảo ~RateErrorModel ();
};
#endif

Một vài điều cần lưu ý ở đây. Chúng ta cần bao gồm đối tượng.h. Công ước ở ns-3 đó là nếu
tệp tiêu đề được đặt trong cùng một thư mục, nó có thể được đưa vào mà không cần bất kỳ đường dẫn nào
tiếp đầu ngữ. Do đó, nếu chúng tôi triển khai ErrorModel trong src/lõi/mô hình thư mục, chúng tôi
có thể vừa nói "#include "đối tượng.h"". Nhưng chúng ta đang ở trong src/mạng/mô hình, vì vậy chúng ta phải
bao gồm nó dưới dạng "#include "ns3/object.h"". Cũng lưu ý rằng điều này nằm ngoài không gian tên
tờ khai.

Thứ hai, mỗi lớp phải thực hiện một hàm thành viên công khai tĩnh được gọi là GetTypeId (vô hiệu).

Thứ ba, đó là một ý tưởng tốt để triển khai các hàm tạo và hàm hủy hơn là để cho
trình biên dịch tạo ra chúng và làm cho hàm hủy trở nên ảo. Trong C++, cũng lưu ý rằng bản sao
toán tử gán và hàm tạo sao chép được tạo tự động nếu chúng không được xác định, vì vậy
nếu bạn không muốn những thứ đó, bạn nên triển khai chúng với tư cách là thành viên riêng tư. Khía cạnh này của
C++ được thảo luận trong cuốn sách C++ hiệu quả của Scott Meyers. mục 45.

Bây giờ chúng ta hãy xem một số mã triển khai khung tương ứng trong tệp .cc.:

#include "error-model.h"

không gian tên ns3 {

NS_OBJECT_ENSURE_REGISTERED (Mô hình lỗi);

TypeId ErrorModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::ErrorModel")
.SetParent ()
;
trả lại tid;
}

ErrorModel::ErrorModel ()
{
}

ErrorModel::~ErrorModel ()
{
}

NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);

TypeId RateErrorModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
;
trả lại tid;
}

RateErrorModel::RateErrorModel ()
{
}

RateErrorModel::~RateErrorModel ()
{
}

Là gì GetTypeId (vô hiệu) chức năng? Chức năng này thực hiện một số điều. Nó đăng ký một
chuỗi duy nhất vào hệ thống TypeId. Nó thiết lập hệ thống phân cấp của các đối tượng trong
hệ thống thuộc tính (thông qua SetParent). Nó cũng tuyên bố rằng một số đối tượng nhất định có thể được tạo thông qua
khung tạo đối tượng (AddConstructor).

Macro NS_OBJECT_ENSURE_REGISTERED (tên lớp) cũng cần một lần cho mỗi lớp
định nghĩa một phương thức GetTypeId mới và nó thực hiện đăng ký thực sự của lớp vào
hệ thống. Chương Mô hình đối tượng sẽ thảo luận chi tiết hơn về vấn đề này.

Dịch vụ SAP bao gồm Bên ngoài Các Tập Tin
Logging cá nhân hóa
Ở đây, viết a bit về thêm |ns3| khai thác gỗ macro. Lưu ý việc này LOG_COMPONENT_DEFINE is
thực hiện bên ngoài các không gian tên Ns3

Người xây dựng, Trống Chức năng Sản phẩm mẫu
Key Biến (Vỡ nợ Giá trị, Thuộc tính)
Thử nghiệm chương trình 1
Đối tượng Khung
Thêm a Mâu Script
Tại thời điểm này, người ta có thể muốn thử lấy giàn giáo cơ bản được xác định ở trên và thêm nó vào
vào hệ thống. Việc thực hiện bước này bây giờ cho phép người ta sử dụng một mô hình đơn giản hơn khi sửa ống nước.
vào hệ thống và cũng có thể tiết lộ liệu có cần sửa đổi bất kỳ thiết kế hoặc API nào không
làm ra. Sau khi hoàn thành việc này, chúng ta sẽ quay lại xây dựng chức năng của
Bản thân ErrorModels.

Thêm Cơ bản cá nhân hóa in các Lớp
/* điểm-điểm-net-device.h */
lớp ErrorModel;

/ **
* Mô hình lỗi khi nhận các sự kiện gói
*/
Ptr m_receiveErrorModel;

Thêm Phụ kiện
làm mất hiệu lực
PointToPointNetDevice::SetReceiveErrorModel (Ptr em)
{
NS_LOG_FUNCTION (cái này << em);
m_receiveErrorModel = em;
}

.AddAttribution ("NhậnErrorModel",
"Mô hình lỗi máy thu được sử dụng để mô phỏng việc mất gói",
Giá trị con trỏ (),
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker ())

dây dọi trong các WELFARE
void PointToPointNetDevice::Nhận (Ptr gói)
{
NS_LOG_FUNCTION (gói << này);
giao thức uint16_t = 0;

if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (gói) )
{
//
// Nếu chúng ta có một mô hình lỗi và nó chỉ ra rằng đã đến lúc mất đi một
// gói bị hỏng, đừng chuyển tiếp gói này lên, hãy để nó đi.
//
m_dropTrace (gói);
}
khác
{
//
// Nhấn vào móc theo dõi nhận, loại bỏ tiêu đề giao thức điểm-điểm
// và chuyển tiếp gói này lên ngăn xếp giao thức.
//
m_rxTrace (gói);
ProcessHeader(gói, giao thức);
m_rxCallback (cái này, gói, giao thức, GetRemote ());
if (!m_promiscCallback.IsNull())
{ m_promiscCallback (cái này, gói, giao thức, GetRemote (),
GetAddress (), NetDevice::PACKET_HOST);
}
}
}

Tạo Null chức năng Script
/* simple-error-model.cc */

// Mô hình lỗi
// Chúng tôi muốn thêm một mô hình lỗi vào NetDevice của nút 3
// Chúng ta có thể lấy một điều khiển cho NetDevice thông qua kênh và nút
// con trỏ
Ptr nd3 = PointToPointTopology::GetNetDevice
(n3, kênh2);
Ptr em = Tạo ();
nd3->SetReceiveErrorModel (em);

bool
ErrorModel::DoCorrupt (Gói & p)
{
NS_LOG_FUNCTION;
NS_LOG_UNCOND("Hỏng!");
return false;
}

Tại thời điểm này, chúng ta có thể chạy chương trình với ErrorModel tầm thường được đưa vào phần nhận
đường dẫn của PointToPointNetDevice. Nó in ra chuỗi "Tham nhũng!" cho mỗi gói
nhận được tại nút n3. Tiếp theo, chúng ta quay lại mô hình lỗi để thêm vào một lớp con thực hiện
mô hình lỗi thú vị hơn.

Thêm a Lớp con
Lớp cơ sở tầm thường ErrorModel không làm được điều gì thú vị nhưng nó cung cấp một
giao diện lớp cơ sở hữu ích (Corrupt () và Reset ()), được chuyển tiếp tới các hàm ảo
có thể được phân lớp. Tiếp theo chúng ta hãy xem xét cái mà chúng ta gọi là BasicErrorModel dựa trên
các ns-2 Lớp ErrorModel (trong ns-2/queue/errmodel.{cc,h}).

Chúng ta muốn nó có những thuộc tính gì, từ góc độ giao diện người dùng? Chúng tôi muốn
để người dùng có thể trao đổi một cách dễ dàng loại ErrorModel được sử dụng trong
NetDevice. Chúng tôi cũng muốn có khả năng thiết lập các tham số có thể định cấu hình.

Dưới đây là một vài yêu cầu đơn giản mà chúng tôi sẽ xem xét:

· Khả năng thiết lập biến ngẫu nhiên chi phối tổn thất (mặc định là Biến thống nhất)

· Khả năng thiết lập đơn vị (bit, byte, gói, thời gian) chi tiết về lỗi xảy ra
đã áp dụng.

· Có khả năng thiết lập tỷ lệ lỗi (ví dụ 10^-3) tương ứng với đơn vị trên
độ chi tiết.

· Khả năng bật/tắt (mặc định là bật)

Làm thế nào đến Lớp con
Chúng ta khai báo BasicErrorModel là một lớp con của ErrorModel như sau:

lớp BasicErrorModel : ErrorModel công khai
{
công khai:
TypeId tĩnh GetTypeId (void);
...
riêng tư:
// Triển khai các hàm ảo thuần túy của lớp cơ sở
bool ảo DoCorrupt (Ptr P);
bool ảo DoReset (void);
...
}

và định cấu hình hàm GetTypeId của lớp con bằng cách đặt chuỗi TypeId duy nhất và
đặt Parent thành ErrorModel:

TypeId RateErrorModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent ()
.AddConstructor ()
...

Xây dựng Trung tâm Chức năng đơn vị Kiểm tra
Khẳng định Macros
Writing đơn vị Kiểm tra
Thêm a Mới Mô-đun đến ns-3
Khi bạn đã tạo một nhóm các lớp, ví dụ và bài kiểm tra có liên quan, chúng có thể
kết hợp với nhau thành một ns-3 mô-đun để chúng có thể được sử dụng với các mô-đun hiện có ns-3 mô-đun
và bởi các nhà nghiên cứu khác.

Chương này hướng dẫn bạn các bước cần thiết để thêm một mô-đun mới vào ns-3.

Bước 0 - Mô-đun Bố trí
Tất cả các mô-đun có thể được tìm thấy trong src danh mục. Mỗi mô-đun có thể được tìm thấy trong một thư mục
có cùng tên với mô-đun. Ví dụ, quang phổ mô-đun có thể được tìm thấy ở đây:
src/phổ. Chúng tôi sẽ trích dẫn từ quang phổ mô-đun để minh họa.

Một mô-đun nguyên mẫu có cấu trúc thư mục và các tệp cần thiết sau:

src /
tên mô-đun/
ràng buộc/
doc /
ví dụ /
chữ viết
người giúp đỡ/
người mẫu/
kiểm tra/
ví dụ-to-run.py
chữ viết

Không phải tất cả các thư mục sẽ có mặt trong mỗi mô-đun.

Bước 1 - Tạo a Mô-đun Bộ xương
Một chương trình python được cung cấp trong thư mục nguồn sẽ tạo khung cho một
mô-đun. Vì mục đích của cuộc thảo luận này, chúng tôi sẽ giả định rằng mô-đun mới của bạn được gọi là
mô-đun mới. Từ src thư mục, hãy làm như sau để tạo mô-đun mới:

$ ./create-module.py mới-mô-đun

Tiếp theo, cd trong mô-đun mới; bạn sẽ tìm thấy bố cục thư mục này:

$ cd mô-đun mới
$ls
ví dụ về tài liệu trợ giúp kiểm tra mô hình wscript

Chi tiết hơn, tạo-module.py script sẽ tạo các thư mục cũng như ban đầu
bộ xương chữ viết, .h, . Cc.đầu tiên các tập tin. Mô-đun hoàn chỉnh với các tập tin khung trông
như thế này:

src /
mô-đun mới/
doc /
mô-đun mới.rst
ví dụ /
mô-đun mới-example.cc
chữ viết
người giúp đỡ/
new-module-helper.cc
mô-đun mới-helper.h
người mẫu/
mô-đun mới.cc
mô-đun mới.h
kiểm tra/
new-module-test-suite.cc
chữ viết

(Nếu được yêu cầu ràng buộc/ thư mục được liệt kê trong Bước-0 sẽ được tạo tự động trong thời gian
tòa nhà.)

Tiếp theo chúng ta sẽ hướng dẫn cách tùy chỉnh mô-đun này. thông báo WAF về các tập tin mà
việc tạo mô-đun của bạn được thực hiện bằng cách chỉnh sửa hai chữ viết các tập tin. Chúng ta sẽ đi bộ qua
các bước chính trong chương này.

Tất cả ns-3 các mô-đun phụ thuộc vào cốt lõi module và thường là trên các mô-đun khác. Sự phụ thuộc này
được chỉ định trong chữ viết tập tin (ở cấp cao nhất của mô-đun, không phải tệp riêng biệt chữ viết
tập tin trong ví dụ danh mục!). Trong bộ xương chữ viết cuộc gọi sẽ khai báo của bạn
mô-đun mới để WAF sẽ trông như thế này (trước khi chỉnh sửa):

xây dựng chắc chắn (bld):
mô-đun = bld.create_ns3_module('mô-đun mới', ['core'])

Hãy giả sử rằng mô-đun mới Phụ thuộc vào internet, di độngaodv mô-đun. Sau đó
chỉnh sửa nó chữ viết tập tin sẽ trông giống như:

xây dựng chắc chắn (bld):
mô-đun = bld.create_ns3_module('mô-đun mới', ['internet', 'di động', 'aodv'])

Lưu ý rằng chỉ nên liệt kê các phần phụ thuộc của mô-đun cấp đầu tiên, đó là lý do tại sao chúng tôi đã xóa
cốt lõi; Các internet mô-đun lần lượt phụ thuộc vào cốt lõi.

Mô-đun của bạn rất có thể sẽ có các tệp nguồn mô hình. Bộ xương ban đầu (sẽ
biên dịch thành công) được tạo trong model/new-module.ccmô hình/mô-đun mới.h.

Nếu mô-đun của bạn có các tệp nguồn trợ giúp thì chúng sẽ đi vào người giúp đỡ/
danh mục; một lần nữa, các khung ban đầu được tạo trong thư mục đó.

Cuối cùng, cách tốt nhất là viết bài kiểm tra và ví dụ. Những điều này gần như chắc chắn sẽ
cần thiết để các mô-đun mới được chấp nhận vào chính thức ns-3 cây nguồn Một bộ xương
bộ thử nghiệm và trường hợp thử nghiệm được tạo trong kiểm tra/ danh mục. Bộ thử nghiệm khung xương sẽ
chứa hàm tạo bên dưới, khai báo một bài kiểm tra đơn vị mới có tên mô-đun mới, Với một
trường hợp thử nghiệm duy nhất bao gồm lớp Mô-đun mớiTestCase1:

NewModuleTestSuite::NewModuleTestSuite ()
: TestSuite ("mô-đun mới", ĐƠN VỊ)
{
AddTestCase (NewModuleTestCase1 mới);
}

Bước 3 - Khai báo nguồn Các Tập Tin
Các tệp mã nguồn và tiêu đề công khai cho mô-đun mới của bạn phải được chỉ định trong
chữ viết tập tin bằng cách sửa đổi nó bằng trình soạn thảo văn bản của bạn.

Ví dụ: sau khi khai báo quang phổ mô-đun, src/phổ/wscript chỉ định
tập tin mã nguồn với danh sách sau:

xây dựng chắc chắn (bld):

module = bld.create_ns3_module('phổ', ['internet', 'lan truyền', 'ăng-ten', 'ứng dụng'])

mô-đun.source = [
'model/spectrum-model.cc',
'model/spectrum-value.cc',
.
.
.
'model/microwave-oven-spectrum-value-helper.cc',
'người trợ giúp/spectrum-helper.cc',
'helper/adhoc-aloha-noack-ideal-phy-helper.cc',
'helper/waveform-generator-helper.cc',
'helper/spectrum-analyzer-helper.cc',
]

Các đối tượng thu được từ việc biên soạn các nguồn này sẽ được tập hợp thành một thư viện liên kết,
sẽ được liên kết với bất kỳ chương trình nào dựa trên mô-đun này.

Nhưng làm cách nào để các chương trình như vậy tìm hiểu API công khai của mô-đun mới của chúng tôi? Đọc tiếp!

Bước 4 - Khai báo Public Tiêu đề Các Tập Tin
Các tệp tiêu đề xác định API công khai của mô hình của bạn và các trình trợ giúp cũng phải được
được chỉ định trong chữ viết tập tin.

Tiếp tục với quang phổ minh họa mô hình, các tệp tiêu đề công khai được chỉ định
với khổ thơ sau. (Lưu ý rằng đối số của bld chức năng cho biết WAF đến
cài đặt các tiêu đề của mô-đun này với các tiêu đề khác ns-3 tiêu đề):

tiêu đề = bld(features='ns3header')

headers.module = 'phổ'

tiêu đề.source = [
'model/spectrum-model.h',
'model/spectrum-value.h',
.
.
.
'model/microwave-oven-spectrum-value-helper.h',
'người trợ giúp/spectrum-helper.h',
'người trợ giúp/adhoc-aloha-noack-ideal-phy-helper.h',
'helper/waveform-generator-helper.h',
'người trợ giúp/phân tích quang phổ-helper.h',
]

Các tiêu đề được công khai theo cách này sẽ có thể truy cập được đối với người dùng mô hình của bạn, bao gồm
những tuyên bố như

#include "ns3/spectrum-model.h"

Các tiêu đề được sử dụng nghiêm ngặt trong nội bộ trong quá trình triển khai của bạn không nên được đưa vào đây. Họ
bạn vẫn có thể truy cập được vào việc triển khai của mình bằng cách bao gồm các câu lệnh như

#include "my-module-implementation.h"

Bước 5 - Khai báo Kiểm tra
Nếu mô-đun mới của bạn có các bài kiểm tra thì chúng phải được chỉ định trong chữ viết nộp hồ sơ bởi
sửa đổi nó bằng trình soạn thảo văn bản của bạn.

quang phổ kiểm tra mô hình được chỉ định với đoạn thơ sau:

module_test = bld.create_ns3_module_test_library('spectrum')

module_test.source = [
'test/spectrum-interference-test.cc',
'kiểm tra/phổ-giá trị-test.cc',
]

Xem Kiểm tra để biết thêm thông tin về cách viết trường hợp thử nghiệm.

Bước 6 - Khai báo Các ví dụ
Nếu mô-đun mới của bạn có các ví dụ thì chúng phải được chỉ định trong ví dụ/wscript
tài liệu. (Bộ xương cấp cao nhất chữ viết sẽ bao gồm đệ quy ví dụ/wscript chỉ nếu
các ví dụ đã được bật tại thời điểm định cấu hình.)

quang phổ mô hình xác định đây là ví dụ đầu tiên trong src/phổ/ví dụ/wscript với

xây dựng chắc chắn (bld):
obj = bld.create_ns3_program('adhoc-aloha-ideal-phy',
['phổ', 'tính di động'])
obj.source = 'adhoc-aloha-ideal-phy.cc'

Lưu ý rằng đối số thứ hai của hàm create_ns3_program() là danh sách các mô-đun
mà chương trình được tạo phụ thuộc vào; một lần nữa, đừng quên bao gồm mô-đun mới in
danh sách. Cách tốt nhất là chỉ liệt kê các phụ thuộc mô-đun trực tiếp và để WAF
suy ra cây phụ thuộc đầy đủ.

Đôi khi, để rõ ràng, bạn có thể muốn phân chia việc triển khai ví dụ của mình cho
một số tập tin nguồn. Trong trường hợp này, chỉ bao gồm các tệp đó dưới dạng rõ ràng bổ sung
nguồn của ví dụ:

obj = bld.create_ns3_program('new-module-example', [new-module])
obj.source = ['new-module-example.cc', 'new-module-example-part.cc']

Các ví dụ Python được chỉ định bằng cách sử dụng lệnh gọi hàm sau. Lưu ý rằng thứ hai
đối số cho hàm register_ns3_script() là danh sách các mô-đun mà Python
ví dụ phụ thuộc vào:

bld.register_ns3_script('new-module-example.py', ['new-module'])

Bước 7 - Các ví dụ chạy as Kiểm tra
Ngoài việc chạy mã kiểm tra rõ ràng, khung kiểm tra cũng có thể được trang bị để
chạy các chương trình ví dụ đầy đủ để cố gắng nắm bắt các hồi quy trong các ví dụ. Tuy nhiên, không phải tất cả
ví dụ phù hợp cho các thử nghiệm hồi quy. Tập tin test/examples-to-run.py kiểm soát
gọi các ví dụ khi khung kiểm tra chạy.

quang phổ ví dụ mô hình được điều hành bởi test.py được chỉ định trong
src/spectrum/test/examples-to-run.py sử dụng hai danh sách C++ và Python sau đây
ví dụ:

# Một danh sách các ví dụ C++ cần chạy để đảm bảo rằng chúng vẫn được duy trì
# có thể xây dựng và chạy được theo thời gian. Mỗi bộ trong danh sách chứa
#
# (example_name, do_run, do_valgrind_run).
#
# Xem test.py để biết thêm thông tin.
cpp_examples = [
("adhoc-aloha-ideal-phy", "Đúng", "Đúng"),
("adhoc-aloha-lý tưởng-phy-với-lò vi sóng", "Đúng", "Đúng"),
("adhoc-aloha-ideal-phy-matrix-propagation-loss-model", "Đúng", "Đúng"),
]

# Danh sách các ví dụ Python sẽ chạy để đảm bảo rằng chúng vẫn được duy trì
# có thể chạy được theo thời gian. Mỗi bộ trong danh sách chứa
#
# (tên_ví dụ, do_run).
#
# Xem test.py để biết thêm thông tin.
python_examples = [
("sample-simulator.py", "Đúng"),
]

Như đã nêu trong nhận xét, mỗi mục trong danh sách ví dụ C++ cần chạy đều chứa
bộ đồ (tên_ví dụ, do_run, do_valgrind_run), Nơi

· tên_ví dụ là tệp thực thi được chạy,

· do_run là điều kiện để chạy ví dụ và

· do_valgrind_run là điều kiện để chạy ví dụ trong valgrind. (Cái này
là cần thiết vì NSC gây ra sự cố hướng dẫn bất hợp pháp với một số bài kiểm tra khi chúng
được chạy dưới valgrind.)

Lưu ý rằng hai điều kiện là các câu lệnh Python có thể phụ thuộc vào WAF cấu hình
biến. Ví dụ,

("tcp-nsc-lfn", "NSC_ENABLED == Đúng", "NSC_ENABLED == Sai"),

Mỗi mục trong danh sách ví dụ Python sẽ chạy đều chứa bộ dữ liệu (tên_ví dụ,
do_run), trong đó, đối với các ví dụ về C++,

· tên_ví dụ là tập lệnh Python sẽ được chạy và

· do_run là điều kiện để chạy ví dụ.

Một lần nữa, điều kiện là một câu lệnh Python có thể phụ thuộc vào WAF các biến cấu hình.
Ví dụ,

("realtime-udp-echo.py", "ENABLE_REAL_TIME == Sai"),

Bước 8 - Thiết lập Xây dựng
Bây giờ bạn có thể định cấu hình, xây dựng và kiểm tra mô-đun của mình như bình thường. Bạn phải cấu hình lại
dự án là bước đầu tiên để WAF lưu trữ thông tin mới trong của bạn chữ viết tệp, hoặc
nếu không mô-đun mới của bạn sẽ không được đưa vào bản dựng.

$ ./waf config --enable -amples --enable-tests
$ ./waf bản dựng
$ ./test.py

Hãy tìm bộ thử nghiệm mô-đun mới của bạn (và các chương trình ví dụ, nếu mô-đun của bạn có bất kỳ
đã bật) trong đầu ra thử nghiệm.

Bước 9 - Python Bindings
Việc thêm các liên kết Python vào mô-đun của bạn là tùy chọn và bước này được nhận xét bởi
mặc định trong tạo-module.py kịch bản.

# bld.ns3_python_binds()

Nếu bạn muốn bao gồm các ràng buộc Python (chỉ cần thiết nếu bạn muốn viết Python ns-3
thay vì các chương trình C++ ns-3), bạn nên bỏ ghi chú ở trên và cài đặt
Hệ thống quét API Python (được đề cập ở phần khác trong hướng dẫn này) và quét mô-đun của bạn để
tạo ra các ràng buộc mới.

Tạo Tài liệu
ns-3 cung cấp hai loại tài liệu: các chương theo phong cách "hướng dẫn sử dụng" mang tính giải thích và
tài liệu API mã nguồn.

Các chương "hướng dẫn sử dụng" được viết bằng tay reStructuredText định dạng (.đầu tiên), là
được xử lý bởi hệ thống tài liệu Python Người khó hiểu để tạo các trang web và tập tin pdf.
Tài liệu API được tạo từ chính mã nguồn, sử dụng doxygen, để tạo ra
các trang web được liên kết chéo. Cả hai điều này đều quan trọng: các chương về Nhân sư giải thích tại sao
và tổng quan về việc sử dụng mô hình; tài liệu API giải thích làm thế nào chi tiết.

Chương này cung cấp một cái nhìn tổng quan nhanh chóng về các công cụ này, nhấn mạnh cách sử dụng ưa thích và
tùy chỉnh cho ns-3.

Để xây dựng tất cả các tài liệu tiêu chuẩn:

$ ./waf tài liệu

Để biết thêm các tùy chọn chuyên biệt, hãy đọc tiếp.

Tài liệu với Người khó hiểu
Chúng tôi sử dụng Người khó hiểu để tạo ra các chương trình bày mô tả thiết kế và cách sử dụng của từng phần
mô-đun. Ngay bây giờ bạn đang đọc Tài liệu Chương. Các Hiển thị nguồn liên kết trong
thanh bên sẽ hiển thị cho bạn nguồn reStructuredText cho chương này.

Thêm Mới chương
Việc thêm một chương mới cần thực hiện ba bước (được mô tả chi tiết hơn bên dưới):

1. Chọn Ở đâu? (các) tệp tài liệu sẽ tồn tại.

2. liên kết từ một trang hiện có đến tài liệu mới.

3. Thêm tệp mới vào makefile.

Ở đâu?
Tài liệu cho một mô-đun cụ thể, foo, bình thường nên vào src/foo/doc/. Ví dụ
src/foo/doc/foo.rst sẽ là tài liệu cấp cao nhất cho mô-đun. Các
src/create-module.py script sẽ tạo tập tin này cho bạn.

Một số mô hình yêu cầu một số .đầu tiên tập tin và số liệu; tất cả những thứ này sẽ được đưa vào
src/foo/doc/ danh mục. Các tài liệu thực sự được xây dựng bởi Sphinx Makefile. Đặc biệt là
tài liệu liên quan, có thể hữu ích nếu có một cơ quan địa phương makefile trong src/foo/doc/
thư mục để đơn giản hóa việc xây dựng tài liệu cho mô-đun này (Antenna là một ví dụ).
Việc thiết lập tính năng này không đặc biệt khó khăn nhưng nằm ngoài phạm vi của chương này.

Trong một số trường hợp, tài liệu trải rộng trên nhiều mô hình; các mạng chương là một ví dụ. TRONG
những trường hợp này thêm .đầu tiên tập tin trực tiếp đến doc/mô hình/nguồn/ có thể thích hợp.

liên kết
Nhân sư phải biết Ở đâu chương mới của bạn sẽ xuất hiện. Trong hầu hết các trường hợp, một mô hình mới
chương sẽ xuất hiện trong mô hình sách. Để thêm chương của bạn vào đó, hãy chỉnh sửa
doc/models/source/index.rst

.. toctree::
:độ sâu tối đa: 1

cơ quan
hình ảnh động
ăng ten
aodv
các ứng dụng
...

Thêm tên tài liệu của bạn (không có .đầu tiên phần mở rộng) vào danh sách này. Xin vui lòng giữ
Lập mô hình các chương theo thứ tự bảng chữ cái để dễ dàng quét trực quan các chương cụ thể.

makefile
Bạn cũng phải thêm tài liệu của mình vào phần thích hợp makefile, Vì vậy làm cho biết kiểm tra nó
để cập nhật. Cuốn sách Mô hình Makefile là doc/mô hình/Makefile, Sách hướng dẫn sử dụng Makefile là
doc/thủ công/Makefile.

# liệt kê tất cả các tệp .st của thư viện mô hình cần được sao chép vào $SOURCETEMP
NGUỒN = \
nguồn/conf.py \
nguồn/_static \
nguồn/index.rst \
nguồn/thay thế.txt \
nguồn/tổ chức.rst \
...
$(SRC)/antenna/doc/source/antenna.rst \
...

Bạn thêm của bạn .đầu tiên tập tin vào NGUỒN Biến đổi. Để thêm số liệu, hãy đọc các bình luận trong phần
makefile để xem biến nào sẽ chứa tệp hình ảnh của bạn. Một lần nữa xin hãy giữ những điều này
theo thứ tự bảng chữ cái.

Xây dựng Người khó hiểu Tài liệu
Xây dựng tài liệu Sphinx khá đơn giản. Để xây dựng tất cả Sphinx
tài liệu:

$ ./waf nhân sư

Để chỉ xây dựng tài liệu Mô hình:

$ tạo -C tài liệu/mô hình

Để xem tài liệu được tạo, hãy trỏ trình duyệt của bạn vào doc/mô hình/xây dựng/html.

Như bạn có thể thấy, Sphinx sử dụng Make để hướng dẫn quy trình. Mục tiêu mặc định xây dựng tất cả
các hình thức đầu ra được kích hoạt, trong đó ns-3 là nhiều trang html, trang đơn đơnhtml
pdf (mủ cao su). Để chỉ xây dựng html nhiều trang, bạn thêm html Mục tiêu:

$ tạo -C doc/mô hình html

Điều này có thể hữu ích để giảm thời gian xây dựng (và quy mô của cuộc thảo luận về xây dựng) khi bạn
đang viết chương của bạn.

Trước khi đưa tài liệu của bạn vào kho lưu trữ, vui lòng kiểm tra xem nó có được xây dựng mà không
lỗi hoặc cảnh báo. Quá trình xây dựng tạo ra rất nhiều kết quả đầu ra (hầu hết là các cuộc trò chuyện thông thường).
từ LaTeX), điều này có thể gây khó khăn cho việc xem liệu có bất kỳ cảnh báo hoặc cảnh báo Sphinx nào không
lỗi. Để tìm các cảnh báo và lỗi quan trọng, chỉ cần xây dựng html phiên bản, sau đó tìm kiếm
nhật ký xây dựng cho cảnh báo or lôi.

ns-3 Chi tiết cụ thể
Tượng Nhân sư tài liệu hướng dẫnhướng dẫn khá tốt. Chúng tôi sẽ không lặp lại những điều cơ bản
ở đây, thay vì tập trung vào cách sử dụng ưu tiên cho ns-3.

· Bắt đầu văn bản với hai dòng sau:

.. bao gồm:: thay thế.txt
.. đánh dấu:: cpp

Dòng đầu tiên cho phép một số thay thế đơn giản. Ví dụ như gõ |ns3| biểu hiện như
ns-3. Cái thứ hai đặt ngôn ngữ đánh dấu mã nguồn mặc định một cách rõ ràng cho
tệp, vì dự đoán của trình phân tích cú pháp không phải lúc nào cũng chính xác. (Cũng có thể thiết lập
ngôn ngữ rõ ràng cho một khối mã duy nhất, xem bên dưới.)

· Phần:

Sphinx khá tự do trong việc đánh dấu các tiêu đề của phần. Theo quy ước, chúng tôi thích điều này
hệ thống cấp bậc:

.. phân cấp tiêu đề:
------------- Chương
************* Phần (#.#)
============== Tiểu mục (#.#.#)
############# Tiểu mục

· Đánh dấu cú pháp:

Để sử dụng công cụ tô sáng cú pháp mặc định, chỉ cần bắt đầu một khối mã nguồn:

┌─────────────────────────────────────── ───────┬── ───────────────────────────────┐
│Nguồn Sphinx │ Kết xuất đầu ra │
├─────────────────────────────────────── ───────┼── ───────────────────────────────┤
│ │ Cái Frobnitz được truy cập bởi: │
│ ``Frobnitz`` được truy cập bởi:: │ │
│ │ Foo::Frobnitz Frobnitz; │
│ Foo::Frobnitz Frob; │frob.Set (...); │
│frob.Set (...); │ │
└─────────────────────────────────────── ───────┴── ───────────────────────────────┘

Ví dụ: để sử dụng một công cụ đánh dấu cú pháp cụ thể, bash lệnh vỏ:

┌─────────────────────────────────┬───── ────────── ───┐
│Nguồn Sphinx │ Kết xuất đầu ra │
├─────────────────────────────────┼───── ────────── ───┤
│ │ │
│ .. mã nguồn:: bash │ $ ls │
│ │ │
│ $ ls │ │
└─────────────────────────────────┴───── ────────── ───┘

· Ký hiệu viết tắt:

Những tốc ký này được định nghĩa:

┌────────────────────────┬────────────── ───┐
│Nguồn Sphinx │ Kết xuất đầu ra │
├────────────────────────┼────────────── ───┤
│ │ ns-3
│ |ns3| │ │
├────────────────────────┼────────────── ───┤
│ │ ns-2
│ |ns2| │ │
├────────────────────────┼────────────── ───┤
│ │ │
│ |kiểm tra| │ │
├────────────────────────┼────────────── ───┤
│ │ RFC 6282
│ :rfc:`6282` │ │
└────────────────────────┴────────────── ───┘

Tài liệu với doxygen
Chúng tôi sử dụng doxygen để tạo ra có thể duyệt được Tài liệu API. Doxygen cung cấp một số
các tính năng hữu ích:

· Bảng tổng hợp của các thành viên trong lớp.

· Đồ thị kế thừa và cộng tác cho tất cả các lớp.

· Liên kết tới mã nguồn thực hiện từng chức năng.

· Liên kết đến mọi nơi thành viên được sử dụng.

· Liên kết tới mọi đối tượng được sử dụng để thực hiện một chức năng.

· Nhóm các lớp liên quan, chẳng hạn như tất cả các lớp liên quan đến một giao thức cụ thể.

Ngoài ra, chúng tôi sử dụng loạiId hệ thống để thêm vào tài liệu cho mỗi lớp

· Các Config đường đi mà các đối tượng đó có thể tiếp cận được.

· Tài liệu cho bất kỳ Thuộc tính, Bao gồm cả Thuộc tính được định nghĩa trong các lớp cha.

· Tài liệu cho bất kỳ Dấu vết nguồn được xác định bởi lớp.

Doxygen hoạt động bằng cách quét mã nguồn, tìm kiếm những bình luận được đánh dấu đặc biệt. Nó
cũng tạo ra một tham chiếu chéo, cho biết Ở đâu mỗi tệp, lớp, phương thức và biến là
đã sử dụng.

Ưa thích Phong cách
Kiểu ưa thích cho các nhận xét Doxygen là kiểu JavaDoc:

/ **
* Mô tả ngắn gọn về lớp hoặc phương pháp này.
* Các dòng liền kề trở thành một đoạn văn duy nhất.
*
* Mô tả dài hơn, có nhiều chi tiết.
*
* Dòng trống ngăn cách các đoạn văn.
*
* Giải thích lớp hoặc phương thức làm gì, sử dụng thuật toán gì.
* Giải thích đơn vị của đối số và giá trị trả về.
*
* \note Lưu ý mọi hạn chế hoặc vấn đề cần khắc phục.
*
* (Đối với các hàm có đối số hoặc giá trị trả về :)
* \param foo Cụm danh từ ngắn gọn mô tả lập luận này.
* \param bar Lưu ý Trường hợp câu và dấu chấm câu.
* \return Cụm danh từ ngắn gọn mô tả giá trị.
*
* \nội bộ
*
* Bạn cũng có thể thảo luận chi tiết triển khai nội bộ.
* Không cần thiết phải hiểu tài liệu này khi sử dụng
* lớp hoặc phương thức.
*/
lớp Ví dụ

Trong phong cách này, khối chú thích Doxygen bắt đầu bằng hai ký tự `*': / **, và đứng trước
mục đang được ghi lại.

Đối với những hạng mục chỉ cần mô tả ngắn gọn, một trong hai hình thức ngắn gọn sau đây đều phù hợp:

/** Triển khai hàm hủy. */
void DoDispose ();

int m_count; //!< Đếm ...

Lưu ý dạng đặc biệt của nhận xét cuối dòng, //!, chỉ ra rằng nó đề cập đến
trước mục.

Một số mục cần lưu ý:

· Sử dụng trường hợp câu, bao gồm cả vốn ban đầu.

· Sử dụng dấu câu, đặc biệt là `. ở cuối câu hoặc cụm từ.

· Các \ngắn gọn thẻ không cần thiết; câu đầu tiên sẽ được dùng làm câu tóm tắt
sự miêu tả.

Mỗi lớp, phương thức, typedef, biến thành viên, đối số hàm và giá trị trả về phải
được ghi lại trong tất cả các tệp mã nguồn tạo thành API chính thức và cách triển khai cho
ns-3, Chẳng hạn như src/ /người mẫu/*, src/ /người giúp đỡ/*src/ /utils/*.
Tài liệu về các hạng mục trong src/ /Bài kiểm tra/*src/ /ví dụ/* được ưa thích,
nhưng không bắt buộc.

Hữu ích Tính năng
· Các thành viên được kế thừa sẽ tự động kế thừa tài liệu từ thành viên cha, (nhưng có thể được thay thế
bằng tài liệu địa phương).

1. Ghi lại lớp cơ sở.

2. Trong lớp con đánh dấu các hàm kế thừa bằng một chú thích thông thường:

// Các phương thức kế thừa
khoảng trống ảo FooBar (void);
int ảo BarFoo (baz đôi);

Lưu ý rằng các chữ ký phải khớp chính xác, vì vậy hãy bao gồm đối số chính thức (vô hiệu)

Điều này không hoạt động đối với các hàm tĩnh; nhìn thấy GetTypeId, dưới đây, là một ví dụ.

Xây dựng doxygen Tài liệu
Xây dựng tài liệu Doxygen khá đơn giản:

$ ./waf doxygen

Bản dựng này sử dụng cấu hình mặc định, tạo ra các phần tài liệu cho
tất cả các các mục, ngay cả khi chúng không có khối tài liệu nhận xét rõ ràng. Điều này có
tác dụng ngăn chặn cảnh báo đối với các mục không có giấy tờ nhưng đảm bảo mọi thứ đều xuất hiện
trong đầu ra được tạo ra.

Khi viết tài liệu, việc xem mục nào đang tạo ra thường hữu ích hơn
cảnh báo, thường là về tài liệu bị thiếu. Để xem danh sách cảnh báo đầy đủ, hãy sử dụng
doc/doxygen.warnings.report.sh kịch bản:

$ doc/doxygen.warnings.report.sh
Waf: Vào thư mục `build'
...
Waf: Rời khỏi thư mục `build'
'xây dựng' đã hoàn thành thành công (3 phút 24.094 giây)

Xây dựng lại tài liệu doxygen có đầy đủ lỗi...Xong.

Báo cáo cảnh báo Doxygen
----------------------------------------

(Tất cả số lượng đều là giới hạn dưới.)

Cảnh báo theo mô-đun/thư mục:

Đếm thư mục
----- ----------------------------------
3844 src/lte/mô hình
1718 src/wimax/mô hình
1423 src/lõi/mô hình
....
138 thông số không có giấy tờ bổ sung.
----------------------------------------
Tổng số 15765 cảnh báo
126 thư mục có cảnh báo

Cảnh báo theo tập tin (theo bảng chữ cái)

Đếm tập tin
----- ----------------------------------
17 doc/introspected-doxygen.h
15 ví dụ/routing/manet-routing-compare.cc
26 ví dụ/số liệu thống kê/wifi-example-apps.h
....
----------------------------------------
967 tệp có cảnh báo

Cảnh báo theo tập tin (số)

Đếm tập tin
----- ----------------------------------
374 src/lte/model/lte-asn1-header.h
280 src/lte/model/lte-rrc-sap.h
262 src/lte/model/lte-rrc-header.h
....
----------------------------------------
967 tệp có cảnh báo

Tóm tắt cảnh báo Doxygen
----------------------------------------
126 thư mục
Tệp 967
15765 cảnh báo

Tập lệnh sửa đổi cấu hình để hiển thị tất cả các cảnh báo và rút ngắn thời gian chạy.
Như bạn có thể thấy, tại bài viết này chúng tôi có a rất nhiều của các mặt hàng không có giấy tờ. Báo cáo
tóm tắt các cảnh báo theo mô-đun src/*/*và theo tập tin, theo thứ tự bảng chữ cái và số.

Tập lệnh có một số tùy chọn để giảm bớt mọi thứ và làm cho việc này dễ quản lý hơn. Để được giúp đỡ,
sử dụng -h lựa chọn. Đã chạy nó một lần để thực hiện quá trình xây dựng Doxygen và tạo toàn bộ
nhật ký cảnh báo, bạn có thể xử lý lại tệp nhật ký bằng nhiều "bộ lọc" khác nhau mà không cần phải thực hiện
bản dựng Doxygen đầy đủ, một lần nữa bằng cách sử dụng -s lựa chọn. Bạn có thể loại trừ cảnh báo khỏi
*/ví dụ/* các tập tin (-e tùy chọn) và/hoặc */Bài kiểm tra/* các tập tin (-t).

Có lẽ tùy chọn hữu ích nhất khi viết bình luận tài liệu là -m , Mà
sẽ giới hạn báo cáo chỉ ở các tệp phù hợp src/ /*, và theo dõi báo cáo với
các dòng cảnh báo thực tế. Kết hợp với ETH và bạn có thể tập trung vào những cảnh báo
cấp bách nhất trong một mô-đun duy nhất:

$ doc/doxygen.warnings.report.sh -m lưới/người trợ giúp
...
Tóm tắt cảnh báo Doxygen
----------------------------------------
1 thư mục
Tệp 3
149 cảnh báo

Cảnh báo được lọc
====================================
src/mesh/helper/dot11s/dot11s-installer.h:72: cảnh báo: Thành viên m_root (biến) của lớp ns3::Dot11sStack không được ghi lại.
src/mesh/helper/dot11s/dot11s-installer.h:35: cảnh báo: kiểu trả về của thành viên ns3::Dot11sStack::GetTypeId không được ghi lại
src/mesh/helper/dot11s/dot11s-installer.h:56: cảnh báo: kiểu trả về của thành viên ns3::Dot11sStack::InstallStack không được ghi lại
src/mesh/helper/flame/lfame-installer.h:40: cảnh báo: Thành viên GetTypeId() (chức năng) của lớp ns3::FlameStack không được ghi lại.
src/mesh/helper/flame/flame-installer.h:60: cảnh báo: kiểu trả về của thành viên ns3::FlameStack::InstallStack không được ghi lại
src/mesh/helper/mesh-helper.h:213: cảnh báo: Thành viên m_nInterfaces (biến) của lớp ns3::MeshHelper không được ghi lại.
src/mesh/helper/mesh-helper.h:214: cảnh báo: Thành viên m_ LannelChannelPolicy (biến) của lớp ns3::MeshHelper không được ghi lại.
src/mesh/helper/mesh-helper.h:215: cảnh báo: Thành viên m_stack (biến) của lớp ns3::MeshHelper không được ghi lại.
src/mesh/helper/mesh-helper.h:216: cảnh báo: Thành viên m_stackFactory (biến) của lớp ns3::MeshHelper không được ghi lại.
src/mesh/helper/mesh-helper.h:209: cảnh báo: các tham số của thành viên ns3::MeshHelper::CreateInterface không được ghi lại (tất cả)
src/mesh/helper/mesh-helper.h:119: cảnh báo: các tham số của thành viên ns3::MeshHelper::SetStandard không được ghi lại (tất cả)

Bây giờ vấn đề chỉ là hiểu mã và viết một số tài liệu!

ns-3 Chi tiết cụ thể
Đối với Sphinx, Doxygen tài liệutài liệu tham khảo khá tốt. Chúng tôi sẽ không sao chép
những điều cơ bản ở đây, thay vì tập trung vào cách sử dụng ưu tiên cho ns-3.

· Sử dụng Doxygen Modules để nhóm các mục liên quan.

Trong tiêu đề chính cho mô-đun, hãy tạo nhóm Doxgyen:

/ **
* \defgroup giao thức foo Foo.
*/

Đánh dấu mỗi lớp liên kết là thuộc về nhóm:

/ **
* \inggroup foo
*
* Kiểu gói Foo.
*/
lớp học

· Bạn có biết không đánh máy có thể có lập luận chính thức? Điều này cho phép tài liệu về chức năng
chữ ký con trỏ:

/ **
* Chữ ký chức năng gọi lại thanh.
*
* \param ale Kích thước của một lít bia, tính bằng ounce Imperial.
*/
typedef void (* BarCallback)(const int ale);

· Sao chép đặc tính chuỗi trợ giúp từ GetTypeId phương pháp sử dụng làm bản tóm tắt
mô tả của các thành viên liên quan.

· \bugid{298} sẽ tạo liên kết tới lỗi 298 trong Bugzilla của chúng tôi.

· \pname{foo} trong phần mô tả sẽ định dạng foo như là một \param foo tham số, làm cho nó rõ ràng
rằng bạn đang đề cập đến một lập luận thực tế.

· \RFC{301} sẽ tạo liên kết tới RFC 301.

· \nội bộ chỉ nên được sử dụng để bắt đầu một cuộc thảo luận về chi tiết thực hiện, không phải để
dấu riêng chức năng (chúng đã được đánh dấu, như riêng!)

· Đừng tạo các lớp có tên tầm thường, chẳng hạn như tốt nghiệp lớp XNUMX A, ngay cả trong các bộ thử nghiệm. Những cái này
làm cho tất cả các thể hiện của tên lớp theo nghĩa đen `A' được hiển thị dưới dạng các liên kết.

Như đã lưu ý ở trên, các hàm tĩnh không kế thừa tài liệu của các hàm tương tự trong
lớp cha. ns-3 sử dụng một số hàm tĩnh ở mọi nơi; đề xuất
khối tài liệu cho những trường hợp này là:

· Hàm tạo/hàm hủy mặc định:

Lớp học của tôi (); //!< Hàm tạo mặc định
~Lớp của tôi (); //!< Hàm hủy diệt

· Hàm hủy giả và DoDispose:

/** Hàm hủy giả, xem DoDispose. */
~Lớp của tôi ();

/** Triển khai hàm hủy */
khoảng trống ảo DoDispose ();

· GetTypeId:

/ **
* Đăng ký loại này.
* \return Đối tượng TypeId.
*/
TypeId tĩnh GetTypeId (void);

Cho phép Tập hợp con of ns-3 Modules
Giống như hầu hết các dự án phần mềm, ns-3 ngày càng lớn hơn về số lượng mô-đun,
dòng mã và dấu chân bộ nhớ. Tuy nhiên, người dùng chỉ có thể sử dụng một vài mô-đun đó
tại một thời điểm. Vì lý do này, người dùng có thể chỉ muốn kích hoạt rõ ràng tập hợp con của
có thể ns-3 các mô-đun mà họ thực sự cần cho nghiên cứu của mình.

Chương này thảo luận về cách chỉ kích hoạt ns-3 các mô-đun mà bạn đang quan tâm
sử dụng.

Làm thế nào đến cho phép a tập hợp con of ns-3's mô-đun
Nếu các thư viện dùng chung đang được xây dựng thì việc kích hoạt một mô-đun sẽ gây ra ít nhất một
thư viện cần xây dựng:

libns3-modulename.so

Nếu mô-đun có thư viện thử nghiệm và thư viện thử nghiệm đang được xây dựng thì

libns3-modulename-test.so

cũng sẽ được xây dựng. Các mô-đun khác mà mô-đun phụ thuộc và thư viện thử nghiệm của chúng
cũng sẽ được xây dựng.

Theo mặc định, tất cả các mô-đun được tích hợp sẵn ns-3. Có hai cách để kích hoạt một tập hợp con trong số này
mô-đun:

1. Sử dụng tùy chọn --enable-modules của waf

KHAI THÁC. Sử dụng ns-3 tập tin cấu hình

Kích hoạt tính năng mô-đun sử dụng của waf --enable-mô-đun tùy chọn
Ví dụ: để chỉ kích hoạt mô-đun lõi bằng ví dụ và kiểm tra, hãy thử các lệnh sau:

$ ./waf sạch sẽ
$ ./waf cấu hình --enable-examples --enable-tests --enable-modules=core
$ ./waf bản dựng
$ cd xây dựng/gỡ lỗi/
$ls

và các thư viện sau phải có mặt:

các ràng buộc libns3-core.so ns3 các tiện ích đầu
ví dụ mẫu libns3-core-test.so src

Lưu ý ./waff giống cá lăng bước được thực hiện ở đây chỉ để làm rõ hơn thư viện mô-đun nào
được xây dựng. Bạn không cần phải làm ./waff giống cá lăng để kích hoạt các tập hợp con của mô-đun.

Việc chạy test.py sẽ chỉ chạy những thử nghiệm phụ thuộc vào lõi mô-đun:

24 trong 24 bài kiểm tra đã đạt (24 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Lặp lại các bước trên cho mô-đun "mạng" thay vì mô-đun "lõi" và
phần sau đây sẽ được xây dựng, vì mạng phụ thuộc vào lõi:

các ràng buộc libns3-core.so libns3-network.so ns3 các công cụ đầu
ví dụ libns3-core-test.so libns3-network-test.so mẫu src

Việc chạy test.py sẽ khiến các thử nghiệm chỉ phụ thuộc vào mô-đun lõi và mạng bị lỗi.
được chạy:

31 trong 31 bài kiểm tra đã đạt (31 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Kích hoạt tính năng mô-đun sử dụng các ns-3 cấu hình hồ sơ
Tệp cấu hình, .ns3rc, đã được thêm vào ns-3 cho phép người dùng chỉ định cái nào
các mô-đun phải được đưa vào bản dựng.

Khi kích hoạt một tập hợp con của ns-3 module, các quy tắc ưu tiên như sau:

1. chuỗi --enable-modules cấu hình sẽ ghi đè bất kỳ tệp .ns3rc nào

2. tệp .ns3rc ở cấp cao nhất ns-3 thư mục được tư vấn tiếp theo, nếu có

3. hệ thống tìm kiếm ~/.ns3rc nếu hai điều trên không được chỉ định

Nếu không có điều nào ở trên giới hạn các mô-đun được xây dựng thì tất cả các mô-đun mà waf biết về sẽ
được xây dựng.

Phiên bản được duy trì của tệp .ns3rc trong ns-3 kho mã nguồn nằm ở
các utils danh mục. Lý do cho điều này là nếu nó nằm trong thư mục cấp cao nhất của
kho lưu trữ, nó sẽ dễ bị kiểm tra ngẫu nhiên từ những người bảo trì cho phép
mô-đun họ muốn sử dụng. Do đó, người dùng cần sao chép thủ công .ns3rc từ
utils thư mục đến vị trí ưa thích của họ (thư mục cấp cao nhất hoặc thư mục chính của họ) để
cho phép cấu hình xây dựng mô-đun liên tục.

Giả sử bạn đang ở cấp cao nhất ns-3 thư mục, bạn có thể lấy một bản sao của .ns3rc
tập tin nằm trong utils thư mục như sau:

$ cp utils/.ns3rc .

Tệp .ns3rc bây giờ sẽ ở cấp cao nhất của bạn ns-3 thư mục và nó chứa
Sau đây:

#! / usr / bin / env mãng xà

# Danh sách các module sẽ được kích hoạt khi ns-3 được chạy.
# Các mô-đun phụ thuộc vào các mô-đun được liệt kê cũng sẽ được bật.
#
# Tất cả các mô-đun có thể được kích hoạt bằng cách chọn 'all_modules'.
module_enabled = ['all_modules']

# Đặt giá trị này bằng true nếu bạn muốn chạy các ví dụ.
ví dụ_enabled = Sai

# Đặt giá trị này bằng true nếu bạn muốn chạy thử nghiệm.
test_enabled = Sai

Sử dụng trình chỉnh sửa yêu thích của bạn để sửa đổi tệp .ns3rc để chỉ kích hoạt mô-đun lõi với
ví dụ và bài kiểm tra như thế này:

#! / usr / bin / env mãng xà

# Danh sách các module sẽ được kích hoạt khi ns-3 được chạy.
# Các mô-đun phụ thuộc vào các mô-đun được liệt kê cũng sẽ được bật.
#
# Tất cả các mô-đun có thể được kích hoạt bằng cách chọn 'all_modules'.
module_enabled = ['core']

# Đặt giá trị này bằng true nếu bạn muốn chạy các ví dụ.
ví dụ_enabled = Đúng

# Đặt giá trị này bằng true nếu bạn muốn chạy thử nghiệm.
test_enabled = Đúng

Bây giờ chỉ mô-đun lõi mới được kích hoạt nếu bạn thử các lệnh sau:

$ ./waf sạch sẽ
$ ./waf cấu hình
$ ./waf bản dựng
$ cd xây dựng/gỡ lỗi/
$ls

và các thư viện sau phải có mặt:

các ràng buộc libns3-core.so ns3 các tiện ích đầu
ví dụ mẫu libns3-core-test.so src

Lưu ý ./waff giống cá lăng bước được thực hiện ở đây chỉ để làm rõ hơn thư viện mô-đun nào
được xây dựng. Bạn không cần phải làm ./waff giống cá lăng để kích hoạt các tập hợp con của mô-đun.

Việc chạy test.py sẽ chỉ chạy những thử nghiệm phụ thuộc vào lõi mô-đun:

24 trong 24 bài kiểm tra đã đạt (24 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Lặp lại các bước trên cho mô-đun "mạng" thay vì mô-đun "lõi" và
phần sau đây sẽ được xây dựng, vì mạng phụ thuộc vào lõi:

các ràng buộc libns3-core.so libns3-network.so ns3 các công cụ đầu
ví dụ libns3-core-test.so libns3-network-test.so mẫu src

Việc chạy test.py sẽ khiến các thử nghiệm chỉ phụ thuộc vào mô-đun lõi và mạng bị lỗi.
được chạy:

31 trong 31 bài kiểm tra đã đạt (31 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Bật/tắt ns-3 Kiểm tra Các ví dụ
ns-3 phân phối bao gồm nhiều ví dụ và thử nghiệm được sử dụng để xác nhận ns-3
hệ thống. Tuy nhiên, người dùng không phải lúc nào cũng muốn chạy các ví dụ và thử nghiệm này cho thiết bị của mình.
cài đặt ns-3.

Chương này thảo luận về cách xây dựng ns-3 có hoặc không có ví dụ và bài kiểm tra của nó.

Làm thế nào đến cho phép vô hiệu hóa ví dụ kiểm tra in ns-3
Có 3 cách để bật/tắt các ví dụ và kiểm tra trong ns-3:

1. Sử dụng build.py khi ns-3 được xây dựng lần đầu tiên

2. Sử dụng waf một lần ns-3 đã được xây dựng

KHAI THÁC. Sử dụng ns-3 tập tin cấu hình một lần ns-3 đã được xây dựng

Cho phép vô hiệu hóa ví dụ kiểm tra sử dụng build.py
Bạn có thể sử dụng build.py để bật/tắt các ví dụ và kiểm tra khi ns-3 được xây dựng lần đầu tiên
thời gian.

Theo mặc định, các ví dụ và bài kiểm tra không được tích hợp sẵn ns-3.

Từ thư mục ns-3-allinone, bạn có thể xây dựng ns-3 không có bất kỳ ví dụ hoặc bài kiểm tra nào đơn giản
bằng cách thực hiện:

$ ./build.py

Chạy test.py ở cấp cao nhất ns-3 thư mục bây giờ sẽ không có ví dụ hoặc bài kiểm tra nào được thực hiện
chạy:

0 trong 0 bài kiểm tra đã đạt (0 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Nếu bạn muốn xây dựng ns-3 với các ví dụ và bài kiểm tra, sau đó thực hiện những việc sau từ phần
thư mục ns-3-allinone:

$ ./build.py --enable -amples --enable-tests

Chạy test.py ở cấp cao nhất ns-3 thư mục sẽ khiến tất cả các ví dụ và bài kiểm tra
được chạy:

170 trong 170 bài kiểm tra đã đạt (170 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Cho phép vô hiệu hóa ví dụ kiểm tra sử dụng WAF
Bạn có thể sử dụng waf để bật/tắt các ví dụ và kiểm tra một lần ns-3 đã được xây dựng.

Theo mặc định, các ví dụ và bài kiểm tra không được tích hợp sẵn ns-3.

Từ cấp cao nhất ns-3 thư mục, bạn có thể xây dựng ns-3 không có bất kỳ ví dụ hoặc bài kiểm tra nào đơn giản
bằng cách thực hiện:

$ ./waf cấu hình
$ ./waf bản dựng

Chạy test.py bây giờ sẽ không có ví dụ hoặc thử nghiệm nào được chạy:

0 trong 0 bài kiểm tra đã đạt (0 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Nếu bạn muốn xây dựng ns-3 với các ví dụ và bài kiểm tra, sau đó thực hiện các bước sau từ đầu
cấp ns-3 danh mục:

$ ./waf config --enable -amples --enable-tests
$ ./waf bản dựng

Việc chạy test.py sẽ khiến tất cả các ví dụ và thử nghiệm được chạy:

170 trong 170 bài kiểm tra đã đạt (170 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Cho phép vô hiệu hóa ví dụ kiểm tra sử dụng các ns-3 cấu hình hồ sơ
Tệp cấu hình, .ns3rc, đã được thêm vào ns-3 cho phép người dùng chỉ định liệu
có nên xây dựng các ví dụ và bài kiểm tra hay không. Bạn có thể sử dụng tập tin này để bật/tắt
ví dụ và kiểm tra một lần ns-3 đã được xây dựng.

Khi kích hoạt việc vô hiệu hóa các ví dụ và kiểm tra, các quy tắc ưu tiên như sau:

1. chuỗi --enable-examples/--disable-examples ghi đè bất kỳ tệp .ns3rc nào

2. chuỗi --enable-tests/--disable-tests ghi đè bất kỳ tệp .ns3rc nào

3. tệp .ns3rc ở cấp cao nhất ns-3 thư mục được tư vấn tiếp theo, nếu có

4. hệ thống tìm kiếm ~/.ns3rc nếu không tìm thấy tệp .ns3rc ở bước trước

Nếu không có điều nào ở trên tồn tại thì các ví dụ và thử nghiệm sẽ không được xây dựng.

Phiên bản được duy trì của tệp .ns3rc trong ns-3 kho mã nguồn nằm ở
các utils danh mục. Lý do cho điều này là nếu nó nằm trong thư mục cấp cao nhất của
kho lưu trữ, nó sẽ dễ bị kiểm tra ngẫu nhiên từ những người bảo trì cho phép
mô-đun họ muốn sử dụng. Do đó, người dùng cần sao chép thủ công .ns3rc từ
utils thư mục đến vị trí ưa thích của họ (thư mục cấp cao nhất hoặc thư mục chính của họ) để
cho phép kích hoạt liên tục các ví dụ và thử nghiệm.

Giả sử bạn đang ở cấp cao nhất ns-3 thư mục, bạn có thể lấy một bản sao của .ns3rc
tập tin nằm trong utils thư mục như sau:

$ cp utils/.ns3rc .

Tệp .ns3rc bây giờ sẽ ở cấp cao nhất của bạn ns-3 thư mục và nó chứa
Sau đây:

#! / usr / bin / env mãng xà

# Danh sách các module sẽ được kích hoạt khi ns-3 được chạy.
# Các mô-đun phụ thuộc vào các mô-đun được liệt kê cũng sẽ được bật.
#
# Tất cả các mô-đun có thể được kích hoạt bằng cách chọn 'all_modules'.
module_enabled = ['all_modules']

# Đặt giá trị này bằng true nếu bạn muốn chạy các ví dụ.
ví dụ_enabled = Sai

# Đặt giá trị này bằng true nếu bạn muốn chạy thử nghiệm.
test_enabled = Sai

Từ cấp cao nhất ns-3 thư mục, bạn có thể xây dựng ns-3 không có bất kỳ ví dụ hoặc bài kiểm tra nào đơn giản
bằng cách thực hiện:

$ ./waf cấu hình
$ ./waf bản dựng

Chạy test.py bây giờ sẽ không có ví dụ hoặc thử nghiệm nào được chạy:

0 trong 0 bài kiểm tra đã đạt (0 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Nếu bạn muốn xây dựng ns-3 với các ví dụ và bài kiểm tra, hãy sử dụng trình chỉnh sửa yêu thích của bạn để thay đổi
các giá trị trong tệp .ns3rc cho tệp example_enabled và test_enabled là True:

#! / usr / bin / env mãng xà

# Danh sách các module sẽ được kích hoạt khi ns-3 được chạy.
# Các mô-đun phụ thuộc vào các mô-đun được liệt kê cũng sẽ được bật.
#
# Tất cả các mô-đun có thể được kích hoạt bằng cách chọn 'all_modules'.
module_enabled = ['all_modules']

# Đặt giá trị này bằng true nếu bạn muốn chạy các ví dụ.
ví dụ_enabled = Đúng

# Đặt giá trị này bằng true nếu bạn muốn chạy thử nghiệm.
test_enabled = Đúng

Từ cấp cao nhất ns-3 thư mục, bạn có thể xây dựng ns-3 với các ví dụ và bài kiểm tra đơn giản bằng cách
đang làm:

$ ./waf cấu hình
$ ./waf bản dựng

Việc chạy test.py sẽ khiến tất cả các ví dụ và thử nghiệm được chạy:

170 trong 170 bài kiểm tra đã đạt (170 đạt, 0 bị bỏ qua, 0 thất bại, 0 bị hỏng, 0 lỗi valgrind)

Xử lý sự cố
Chương này đăng một số thông tin về các lỗi thường gặp khi xây dựng hoặc chạy
ns-3 chương trình.

Xin lưu ý rằng wiki (http://www.nsnam.org/wiki/Troubleshooting) có thể đã đóng góp
mặt hàng.

Xây dựng lỗi
Thời gian chạy lỗi
Đôi khi, lỗi có thể xảy ra với chương trình sau khi xây dựng thành công. Đây là thời gian chạy
lỗi và thường có thể xảy ra khi bộ nhớ bị hỏng hoặc giá trị con trỏ bị thay đổi bất ngờ.
vô giá trị.

Đây là một ví dụ về những gì có thể xảy ra:

$ ./waf --run tcp-point-to-point
Vào thư mục '/home/tomh/ns-3-nsc/build'
Quá trình biên dịch kết thúc thành công
Lệnh ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] đã thoát với mã -11

Thông báo lỗi cho biết chương trình đã kết thúc không thành công nhưng không rõ ràng
từ thông tin này những gì có thể sai. Để kiểm tra kỹ hơn, hãy thử chạy nó dưới
các gdb trình sửa lỗi:

$ ./waf --run tcp-point-to-point --command-template="gdb %s"
Vào thư mục '/home/tomh/ns-3-nsc/build'
Quá trình biên dịch kết thúc thành công
GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh)
Bản quyền 2004 Free Software Foundation, Inc.
GDB là phần mềm miễn phí, được cấp phép bởi Giấy phép Công cộng GNU và bạn
hoan nghênh thay đổi nó và/hoặc phân phối các bản sao của nó theo những điều kiện nhất định.
Nhập "hiển thị sao chép" để xem các điều kiện.
Hoàn toàn không có bảo hành cho GDB. Nhập "hiển thị bảo hành" để biết chi tiết.
GDB này được định cấu hình là "i386-redhat-linux-gnu"...Sử dụng máy chủ libthread_db
thư viện "/lib/libthread_db.so.1".

(gdb) chạy
Chương trình bắt đầu: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point
Đọc các ký hiệu từ đối tượng dùng chung được đọc từ bộ nhớ đích...xong.
Hệ thống đã tải được cung cấp DSO ở mức 0xf5c000

Chương trình nhận được tín hiệu SIGSEGV, Lỗi phân đoạn.
0x0804aa12 trong chính (argc=1, argv=0xbfdfefa4)
tại ../examples/tcp-point-to-point.cc:136
136 điểm localSocket = socketFactory->CreateSocket ();
(gdb) p localSocket
$1 = {m_ptr = 0x3c5d65}
(gdb) p socketFactory
$2 = {m_ptr = 0x0}
(gdb) bỏ
Chương trình đang chạy. Vẫn thoát? (y hoặc n) y

Trước tiên hãy lưu ý cách chương trình được gọi-- truyền lệnh chạy làm đối số cho
mẫu lệnh "gdb %s".

Điều này cho chúng ta biết rằng đã có nỗ lực hủy đăng ký một con trỏ null socketFactory.

Hãy xem dòng 136 của tcp-point-to-point, như gdb gợi ý:

Ptr socketFactory = n2->GetObject (Tcp::iid);
Ptr localSocket = socketFactory->CreateSocket ();
localSocket->Ràng buộc ();

Thủ phạm ở đây là giá trị trả về của GetObject không được kiểm tra và có thể bị
vô giá trị.

Đôi khi bạn có thể cần sử dụng valgrind trí nhớ kiểm tra để tìm ra những lỗi tinh tế hơn. Lại,
bạn gọi việc sử dụng valgrind tương tự:

$ ./waf --run tcp-point-to-point --command-template="valgrind %s"

SOURCE


Tài liệu này được viết bằng reStructuredText cho Người khó hiểu và được duy trì trong
tài liệu/sổ tay thư mục mã nguồn của ns-3.

Sử dụng ns-3-manual trực tuyến bằng dịch vụ onworks.net


Máy chủ & Máy trạm miễn phí

Tải xuống ứng dụng Windows & Linux

Lệnh Linux

Ad




×
quảng cáo
❤️Mua sắm, đặt phòng hoặc mua tại đây — không mất phí, giúp duy trì các dịch vụ miễn phí.