Tiếng AnhTiếng PhápTiếng Tây Ban Nha

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

ns-3-hướng dẫn - Trực tuyến trên đám mây

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

Đây là lệnh ns-3-hướng dẫn 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 giả lập trực tuyến Windows hoặc trình giả lập trực tuyến MAC OS

CHƯƠNG TRÌNH:

TÊN


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

Đây là ns-3 Hướng dẫn. 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 (điều này tài liệu), Thư viện Thủ công và Mô hình cho mới nhất phát hành
phát triển cây

· ns-3 wiki

Tài liệu này được viết bằng reStructuredText cho Người khó hiểu và được duy trì trong
doc / hướng dẫn thư mục mã nguồn của ns-3.

GIỚI THIỆU


Sản phẩm ns-3 simulator là một trình mô phỏng mạng sự kiện rời rạc được nhắm mục tiêu chủ yếu để nghiên cứu
và sử dụng giáo dục. Các ns-3 dự án, bắt đầu vào năm 2006, là một dự án mã nguồn mở
phát triển ns-3.

Mục đích của hướng dẫn này là giới thiệu ns-3 người dùng vào hệ thống trong một
đường. Đôi khi người dùng mới gặp khó khăn trong việc thu thập thông tin cần thiết từ chi tiết
hướng dẫn sử dụng và để chuyển đổi thông tin này thành các mô phỏng hoạt động. Trong hướng dẫn này, chúng tôi
sẽ xây dựng một số mô phỏng ví dụ, giới thiệu và giải thích các khái niệm chính và
các tính năng khi chúng ta đi.

Khi hướng dẫn mở ra, chúng tôi sẽ giới thiệu toàn bộ ns-3 tài liệu và cung cấp
con trỏ đến mã nguồn cho những người quan tâm đến việc tìm hiểu sâu hơn về hoạt động của
hệ thống.

Một số điểm chính đáng chú ý khi bắt đầu:

· ns-3 là mã nguồn mở và dự án cố gắng duy trì một môi trường mở cho
các nhà nghiên cứu để đóng góp và chia sẻ phần mềm của họ.

· ns-3 không phải là phần mở rộng tương thích ngược của ns-2; nó là một trình mô phỏng mới. Cả hai
trình mô phỏng đều được viết bằng C ++ nhưng ns-3 là một trình mô phỏng mới không hỗ trợ
ns-2 API. Một số mô hình từ ns-2 đã được chuyển từ ns-2 đến ns-3. Các
dự án sẽ tiếp tục duy trì ns-2 trong khi ns-3 đang được xây dựng, và sẽ nghiên cứu
cơ chế chuyển đổi và hội nhập.

VỀ CHÚNG TÔI ns-3
ns-3 đã được phát triển để cung cấp một nền tảng mô phỏng mạng mở, có thể mở rộng, cho
nghiên cứu và giáo dục mạng. Tóm lại, ns-3 cung cấp các mô hình về cách dữ liệu gói
mạng hoạt động và thực hiện, đồng thời cung cấp một công cụ mô phỏng để người dùng tiến hành
các thí nghiệm mô phỏng. Một số lý do để sử dụng ns-3 bao gồm để thực hiện các nghiên cứu
khó hơn hoặc không thể thực hiện với các hệ thống thực, để nghiên cứu hành vi của hệ thống
trong một môi trường được kiểm soát cao, có thể tái tạo và để tìm hiểu về cách mạng hoạt động.
Người dùng sẽ lưu ý rằng mô hình có sẵn được đặt trong ns-3 tập trung vào mô hình hóa cách Internet
giao thức và mạng hoạt động, nhưng ns-3 không giới hạn đối với hệ thống Internet; một số người dùng
đang sử dụng ns-3 để mô hình hóa các hệ thống không dựa trên Internet.

Nhiều công cụ mô phỏng tồn tại cho các nghiên cứu mô phỏng mạng. Dưới đây là một số
các tính năng phân biệt của ns-3 ngược lại với các công cụ khác.

· ns-3 được thiết kế như một tập hợp các thư viện có thể được kết hợp với nhau và cũng với các
thư viện phần mềm bên ngoài. Trong khi một số nền tảng mô phỏng cung cấp cho người dùng một
môi trường giao diện người dùng đồ họa tích hợp duy nhất, trong đó tất cả các tác vụ được thực hiện
ngoài, ns-3 là mô-đun hơn trong vấn đề này. Một số hoạt hình bên ngoài và phân tích dữ liệu
và các công cụ trực quan có thể được sử dụng với ns-3. Tuy nhiên, người dùng nên làm việc tại
dòng lệnh và với các công cụ phát triển phần mềm C ++ và / hoặc Python.

· ns-3 chủ yếu được sử dụng trên các hệ thống Linux, mặc dù có hỗ trợ FreeBSD, Cygwin
(dành cho Windows) và hỗ trợ Windows Visual Studio gốc đang trong quá trình
đã phát triển.

· ns-3 không phải là sản phẩm phần mềm được hỗ trợ chính thức của bất kỳ công ty nào. Hỗ trợ cho ns-3
được thực hiện trên cơ sở nỗ lực cao nhất trên danh sách gửi thư của ns-3-người dùng.

Trong ns-2 Người dùng
Đối với những người quen thuộc với ns-2 (một công cụ phổ biến trước đây ns-3), bên ngoài dễ thấy nhất
thay đổi khi chuyển đến ns-3 là sự lựa chọn của ngôn ngữ kịch bản. Các chương trình trong ns-2 đang
được viết kịch bản trong OTcl và kết quả mô phỏng có thể được trực quan hóa bằng Network Animator
nam. Không thể chạy mô phỏng trong ns-2 hoàn toàn từ C ++ (tức là, như một main ()
chương trình không có bất kỳ OTcl). Hơn nữa, một số thành phần của ns-2 được viết bằng C ++ và
những người khác trong OTcl. Trong ns-3, trình mô phỏng được viết hoàn toàn bằng C ++, với Python tùy chọn
ràng buộc. Do đó, các kịch bản mô phỏng có thể được viết bằng C ++ hoặc bằng Python. Họa sĩ hoạt hình mới
và công cụ trực quan hiện có sẵn và đang được phát triển. Từ ns-3 tạo pcap
các tập tin theo dõi gói tin, các tiện ích khác cũng có thể được sử dụng để phân tích dấu vết. Trong này
hướng dẫn, trước tiên chúng ta sẽ tập trung vào việc viết tập lệnh trực tiếp trong C ++ và diễn giải kết quả
thông qua các tập tin dấu vết.

Nhưng cũng có những điểm tương đồng (ví dụ: cả hai đều dựa trên các đối tượng C ++ và một số
mã từ ns-2 đã được chuyển đến ns-3). Chúng tôi sẽ cố gắng làm nổi bật những điểm khác biệt
giữa ns-2ns-3 khi chúng tôi tiếp tục trong hướng dẫn này.

Một câu hỏi mà chúng ta thường nghe là "Tôi có nên sử dụng ns-2 hoặc chuyển đến ns-3? "Trong này
ý kiến ​​của tác giả, trừ khi người dùng được ủy quyền bằng cách nào đó ns-2 (dựa trên hiện có
sự thoải mái cá nhân và kiến ​​thức về ns-2hoặc dựa trên một mô hình mô phỏng cụ thể
chỉ có ở ns-2), người dùng sẽ làm việc hiệu quả hơn với ns-3 cho những điều sau đây
lý do:

· ns-3 được duy trì tích cực với danh sách gửi thư người dùng tích cực, đáp ứng, trong khi ns-2 is
chỉ được duy trì nhẹ và chưa có sự phát triển đáng kể trong cây mã chính của nó
Trong hơn một thập kỷ.

· ns-3 cung cấp các tính năng không có sẵn trong ns-2, chẳng hạn như thực thi mã triển khai
môi trường (cho phép người dùng chạy mã triển khai thực trong trình mô phỏng)

· ns-3 cung cấp mức trừu tượng cơ bản thấp hơn so với ns-2, cho phép nó căn chỉnh
tốt hơn với cách các hệ thống thực được kết hợp với nhau. Một số hạn chế được tìm thấy trong ns-2 (Chẳng hạn như
hỗ trợ nhiều loại giao diện trên các nút một cách chính xác) đã được khắc phục trong ns-3.

ns-2 có một tập hợp các mô-đun đóng góp đa dạng hơn ns-3, do nó dài
Môn lịch sử. Tuy vậy, ns-3 có nhiều mô hình chi tiết hơn trong một số lĩnh vực nghiên cứu phổ biến
(bao gồm các mô hình LTE và WiFi tinh vi) và hỗ trợ mã triển khai
thừa nhận một phổ rất rộng của các mô hình có độ trung thực cao. Người dùng có thể ngạc nhiên khi biết rằng
toàn bộ ngăn xếp mạng Linux có thể được gói gọn trong một ns-3 bằng cách sử dụng Direct
Khung thực thi mã (DCE). ns-2 các mô hình đôi khi có thể được chuyển sang ns-3, đặc biệt
nếu chúng đã được triển khai trong C ++.

Nếu nghi ngờ, một hướng dẫn tốt sẽ là xem xét cả hai trình mô phỏng (cũng như các
trình mô phỏng), và đặc biệt là các mô hình có sẵn cho nghiên cứu của bạn, nhưng hãy nhớ
để trải nghiệm của bạn có thể tốt hơn khi sử dụng công cụ đang được phát triển tích cực và
duy trì (ns-3).

Góp phần
ns-3 là một mô phỏng nghiên cứu và giáo dục, bởi và cho cộng đồng nghiên cứu. Nó sẽ
dựa vào sự đóng góp liên tục của cộng đồng để phát triển các mô hình mới, gỡ lỗi hoặc
duy trì những cái hiện có và chia sẻ kết quả. Có một số chính sách mà chúng tôi hy vọng sẽ
khuyến khích mọi người đóng góp vào ns-3 như họ đã làm cho ns-2:

· Cấp phép nguồn mở dựa trên khả năng tương thích GNU GPLv2

· wiki

· Đóng góp trang, tương tự như ns-2Mã đóng góp phổ biến của trang

· Mở lỗi tracker

Chúng tôi nhận thấy rằng nếu bạn đang đọc tài liệu này, việc đóng góp trở lại cho dự án là
có thể không phải là mối quan tâm hàng đầu của bạn vào thời điểm này, nhưng chúng tôi muốn bạn biết rằng
đóng góp là trên tinh thần của dự án và ngay cả hành động để lại cho chúng tôi một ghi chú
về trải nghiệm ban đầu của bạn với ns-3 (ví dụ: "phần hướng dẫn này không rõ ràng ..."),
báo cáo về tài liệu cũ, vv được đánh giá cao.

Hướng dẫn Cơ quan
Hướng dẫn giả định rằng ban đầu người dùng mới có thể đi theo một đường dẫn như sau:

· Cố gắng tải xuống và xây dựng một bản sao;

· Cố gắng chạy một vài chương trình mẫu;

· Nhìn vào đầu ra mô phỏng và cố gắng điều chỉnh nó.

Do đó, chúng tôi đã cố gắng tổ chức hướng dẫn theo các chuỗi rộng ở trên của
sự kiện.

TÀI NGUYÊN


Sản phẩm web
Có một số tài nguyên quan trọng mà bất kỳ ns-3 người dùng phải nhận thức được. Web chính
trang web được đặt tại http://www.nsnam.org và cung cấp quyền truy cập vào thông tin cơ bản về
ns-3 hệ thống. Tài liệu chi tiết có sẵn trên trang web chính tại
http://www.nsnam.org/documentation/. Bạn cũng có thể tìm thấy các tài liệu liên quan đến hệ thống
kiến trúc từ trang này.

Có một Wiki bổ sung cho chính ns-3 trang web mà bạn sẽ tìm thấy tại
http://www.nsnam.org/wiki/. Bạn sẽ tìm thấy các Câu hỏi thường gặp của người dùng và nhà phát triển ở đó, cũng như
hướng dẫn khắc phục sự cố, mã do bên thứ ba đóng góp, giấy tờ, v.v.

Mã nguồn có thể được tìm thấy và duyệt qua tại http://code.nsnam.org/. Ở đó bạn sẽ tìm thấy
cây phát triển hiện tại trong kho lưu trữ có tên ns-3-dev. Các bản phát hành trước đây và
kho thử nghiệm của các nhà phát triển cốt lõi cũng có thể được tìm thấy ở đó.

lanh lợi
Các hệ thống phần mềm phức tạp cần một số cách để quản lý tổ chức và các thay đổi đối với
mã cơ bản và tài liệu. Có nhiều cách để thực hiện kỳ ​​tích này, và bạn có thể
đã nghe nói về một số hệ thống hiện đang được sử dụng để làm điều này. Đồng thời
Hệ thống phiên bản (CVS) có lẽ được biết đến nhiều nhất.

Sản phẩm ns-3 dự án sử dụng Mercurial làm hệ thống quản lý mã nguồn của nó. Mặc dù bạn không
cần biết nhiều về Mercurial để hoàn thành hướng dẫn này, chúng tôi khuyên bạn nên
làm quen với Mercurial và sử dụng nó để truy cập mã nguồn. Mercurial có một
trang web tại http://www.selenic.com/mercurial/, từ đó bạn có thể lấy mã nhị phân hoặc nguồn
bản phát hành của hệ thống Quản lý Cấu hình Phần mềm (SCM) này. Selenic (nhà phát triển
của Mercurial) cũng cung cấp một hướng dẫn tại
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/và hướng dẫn QuickStart tại
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.

Bạn cũng có thể tìm thấy thông tin quan trọng về việc sử dụng Mercurial và ns-3 trên chính ns-3 web
trang web.

Waf
Khi bạn đã tải mã nguồn xuống hệ thống cục bộ của mình, bạn sẽ cần phải biên dịch
nguồn để tạo ra các chương trình có thể sử dụng được. Cũng như trong trường hợp quản lý mã nguồn, có
có nhiều công cụ để thực hiện chức năng này. Có lẽ là cái được biết đến nhiều nhất trong số này
công cụ là làm cho. Cùng với việc được biết đến nhiều nhất, làm cho có lẽ là khó nhất
để sử dụng trong một hệ thống rất lớn và có cấu hình cao. Bởi vì điều này, nhiều lựa chọn thay thế
đã được phát triển. Gần đây các hệ thống này đã được phát triển bằng Python
ngôn ngữ.

Hệ thống xây dựng Waf được sử dụng trên ns-3 dự án. Nó là một trong những thế hệ mới của
Hệ thống xây dựng dựa trên Python. Bạn sẽ không cần phải hiểu bất kỳ Python nào để xây dựng
hiện tại ns-3 hệ thống.

Đối với những người quan tâm đến các chi tiết đẫm máu của Waf, có thể tìm thấy trang web chính tại
http://code.google.com/p/waf/.

Phát triển Môi trường
Như đã đề cập ở trên, tập lệnh trong ns-3 được thực hiện bằng C ++ hoặc Python. Hầu hết các ns-3 API là
có sẵn bằng Python, nhưng các mô hình được viết bằng C ++ trong cả hai trường hợp. Làm việc
kiến thức về C ++ và các khái niệm hướng đối tượng được giả định trong tài liệu này. Chúng tôi sẽ cầm
một chút thời gian để xem lại một số khái niệm nâng cao hơn hoặc có thể là ngôn ngữ không quen thuộc
các tính năng, thành ngữ và các mẫu thiết kế khi chúng xuất hiện. Chúng tôi không muốn hướng dẫn này
Tuy nhiên, phát triển thành một hướng dẫn C ++, vì vậy chúng tôi mong đợi một lệnh cơ bản của ngôn ngữ này.
Có một số lượng gần như không thể tưởng tượng được các nguồn thông tin về C ++ có sẵn trên
web hoặc in.

Nếu bạn chưa quen với C ++, bạn có thể muốn tìm một cuốn sách hoặc trang web dựa trên hướng dẫn hoặc sách nấu ăn
và làm việc thông qua ít nhất các tính năng cơ bản của ngôn ngữ trước khi tiếp tục. Vì
ví dụ, điều này hướng dẫn.

Sản phẩm ns-3 hệ thống sử dụng một số thành phần của "chuỗi công cụ" GNU để phát triển. MỘT
chuỗi công cụ phần mềm là tập hợp các công cụ lập trình có sẵn trong môi trường nhất định. Vì
đánh giá nhanh về những gì được bao gồm trong chuỗi công cụ GNU, hãy xem,
http://en.wikipedia.org/wiki/GNU_toolchain. ns-3 sử dụng gcc, GNU binutils và gdb.
Tuy nhiên, chúng tôi không sử dụng các công cụ hệ thống xây dựng GNU, không tạo cũng như tự động. Chúng tôi sử dụng Waf
cho các chức năng này.

Điển hình là một ns-3 tác giả sẽ làm việc trong Linux hoặc một môi trường giống như Linux. Cho những người
chạy trong Windows, có tồn tại các môi trường mô phỏng môi trường Linux để
các mức độ khác nhau. Các ns-3 dự án đã được hỗ trợ trong quá khứ (nhưng không phải hiện tại)
phát triển trong môi trường Cygwin cho những người dùng này. Nhìn thấy http://www.cygwin.com/ cho
chi tiết về tải xuống và truy cập ns-3 wiki để biết thêm thông tin về Cygwin và
ns-3. MinGW hiện không được hỗ trợ chính thức. Một thay thế khác cho Cygwin là
cài đặt môi trường máy ảo như máy chủ VMware và cài đặt máy ảo Linux
máy móc.

Ổ cắm Lập trình
Chúng tôi sẽ giả định một cơ sở cơ bản với API Berkeley Sockets trong các ví dụ được sử dụng trong này
hướng dẫn. Nếu bạn chưa quen với ổ cắm, chúng tôi khuyên bạn nên xem lại API và một số cách sử dụng phổ biến
các trường hợp. Để có cái nhìn tổng quan tốt về lập trình các ổ cắm TCP / IP, chúng tôi khuyên bạn nên TCP / IP ổ cắm in
C, Donahoo chuyển đổi.

Có một trang web được liên kết bao gồm nguồn cho các ví dụ trong cuốn sách,
bạn có thể tìm thấy tại: http://cs.baylor.edu/~donahoo/practical/CSockets/.

Nếu bạn hiểu bốn chương đầu của cuốn sách (hoặc cho những ai không có quyền truy cập
vào một bản sao của cuốn sách, các máy khách và máy chủ phản hồi được hiển thị trong trang web ở trên) bạn sẽ
ở trạng thái tốt để hiểu hướng dẫn. Có một cuốn sách tương tự trên Multicast
Ổ cắm, multicast Ổ cắm, Makofske Almeroth. bao gồm tài liệu bạn có thể cần
hiểu nếu bạn nhìn vào các ví dụ đa hướng trong bản phân phối.

NHẬN ĐÃ BẮT ĐẦU


Phần này nhằm mục đích đưa người dùng đến trạng thái làm việc bắt đầu với máy
có thể chưa bao giờ có ns-3 Cài đặt. Nó bao gồm các nền tảng được hỗ trợ, điều kiện tiên quyết, cách để
được ns-3, cách xây dựng ns-3và các cách để xác minh bản dựng và chạy các chương trình đơn giản của bạn.

Giới thiệu chung
ns-3 được xây dựng như một hệ thống các thư viện phần mềm hoạt động cùng nhau. Chương trình người dùng có thể được
đã viết rằng liên kết với (hoặc nhập từ) các thư viện này. Chương trình người dùng được viết bằng
ngôn ngữ lập trình C ++ hoặc Python.

ns-3 được phân phối dưới dạng mã nguồn, có nghĩa là hệ thống đích cần phải có
môi trường phát triển phần mềm để xây dựng thư viện trước, sau đó xây dựng người dùng
chương trình. ns-3 về nguyên tắc có thể được phân phối dưới dạng các thư viện được xây dựng trước cho các
và trong tương lai nó có thể được phân phối theo cách đó, nhưng hiện tại, nhiều người dùng
thực sự làm công việc của họ bằng cách chỉnh sửa ns-3 chính nó, vì vậy có mã nguồn xung quanh để xây dựng lại
các thư viện rất hữu ích. Nếu ai đó muốn đảm nhận công việc chế tạo sẵn
thư viện và các gói dành cho hệ điều hành, vui lòng liên hệ với bộ phận gửi thư ns-Developers
danh sách.

Sau đây, chúng ta sẽ xem xét hai cách tải xuống và xây dựng ns-3. Đầu tiên là
để tải xuống và xây dựng bản phát hành chính thức từ trang web chính. Thứ hai là tìm nạp
và xây dựng các bản sao phát triển của ns-3. Chúng ta sẽ xem xét cả hai ví dụ vì các công cụ
có liên quan hơi khác nhau.

Tải về ns-3
Sản phẩm ns-3 hệ thống nói chung là một hệ thống khá phức tạp và có một số phụ thuộc vào
Các thành phần khác. Cùng với các hệ thống mà bạn rất có thể sẽ xử lý hàng ngày (
GNU toolchain, Mercurial, một trình soạn thảo văn bản), bạn sẽ cần đảm bảo rằng một số
các thư viện bổ sung hiện có trên hệ thống của bạn trước khi tiếp tục. ns-3 cung cấp một wiki
trang bao gồm các trang với nhiều gợi ý và mẹo hữu ích. Một trang như vậy là
Trang "Cài đặt", http://www.nsnam.org/wiki/Installation.

Phần "Điều kiện tiên quyết" của trang wiki này giải thích những gói nào được yêu cầu
hỗ trợ chung ns-3 và cũng cung cấp các lệnh được sử dụng để cài đặt chúng cho
các biến thể Linux phổ biến. Người dùng Cygwin sẽ phải sử dụng trình cài đặt Cygwin (nếu bạn là
Người dùng Cygwin, bạn đã sử dụng nó để cài đặt Cygwin).

Bạn có thể muốn nhân cơ hội này để khám phá ns-3 wiki một chút vì thực sự có
rất nhiều thông tin ở đó.

Từ thời điểm này trở đi, chúng tôi sẽ giả định rằng trình đọc đang làm việc trong Linux hoặc
Môi trường mô phỏng Linux (Linux, Cygwin, v.v.) và đã cài đặt chuỗi công cụ GNU và
được xác minh cùng với các điều kiện tiên quyết được đề cập ở trên. Chúng tôi cũng sẽ giả định rằng
bạn đã cài đặt Mercurial và Waf và chạy trên hệ thống đích.

Sản phẩm ns-3 mã có sẵn trong kho Mercurial trên máy chủ http://code.nsnam.org.
Bạn cũng có thể tải xuống bản phát hành tarball tại http://www.nsnam.org/release/, hoặc bạn có thể làm việc
với kho sử dụng Mercurial. Chúng tôi khuyên bạn nên sử dụng Mercurial trừ khi có một
lý do để không. Xem phần cuối của phần này để biết hướng dẫn về cách lấy tarball
phát hành.

Cách đơn giản nhất để bắt đầu sử dụng kho lưu trữ Mercurial là sử dụng ns-3-allinone
môi trường. Đây là một tập hợp các tập lệnh quản lý việc tải xuống và xây dựng
các hệ thống con khác nhau của ns-3 cho bạn. Chúng tôi khuyên bạn nên bắt đầu ns-3 làm việc trong này
môi trường.

Một cách thực hành là tạo một thư mục có tên là không gian làm việc trong thư mục chính của một người dưới đó
người ta có thể giữ các kho lưu trữ Mercurial tại địa phương. Bất kỳ tên thư mục nào cũng được, nhưng chúng tôi sẽ giả định
việc này không gian làm việc được sử dụng ở đây (lưu ý: còn lại cũng có thể được sử dụng trong một số tài liệu như một
tên thư mục ví dụ).

Tải về ns-3 Sử dụng a Tập tin nén
Tarball là một định dạng cụ thể của kho lưu trữ phần mềm trong đó nhiều tệp được nhóm lại
cùng nhau và có thể nén tệp lưu trữ. ns-3 bản phát hành phần mềm được cung cấp thông qua một
tarball có thể tải xuống. Quá trình tải xuống ns-3 thông qua tarball là đơn giản; bạn chỉ
phải chọn một bản phát hành, tải xuống và giải nén nó.

Giả sử rằng bạn, với tư cách là người dùng, muốn xây dựng ns-3 trong một thư mục cục bộ có tên là
không gian làm việc. Nếu bạn áp dụng không gian làm việc cách tiếp cận thư mục, bạn có thể nhận được một bản sao của một bản phát hành
bằng cách nhập thông tin sau vào trình bao Linux của bạn (thay thế các số phiên bản thích hợp,
Đương nhiên):

$ cd
không gian làm việc $ mkdir
không gian làm việc $ cd
$ wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ tar xjf ns-allinone-3.22.tar.bz2

Nếu bạn thay đổi trong thư mục ns-allinone-3.22 bạn sẽ thấy một số tệp:

$ls
Bake constants.py ns-3.22 README
build.py netanim-3.105 pybindgen-0.16.0.886 use.py

Bây giờ bạn đã sẵn sàng để xây dựng cơ sở ns-3 phân phối.

Tải về ns-3 Sử dụng Nướng
Bake là một công cụ để tích hợp và xây dựng phân tán, được phát triển cho ns-3 dự án.
Bake có thể được sử dụng để tìm nạp các phiên bản phát triển của ns-3 phần mềm và để tải xuống và
xây dựng phần mở rộng cho cơ sở ns-3 phân phối, chẳng hạn như Thực thi mã trực tiếp
môi trường, Cái nôi mô phỏng mạng, khả năng tạo liên kết Python mới và những thứ khác.

Trong gần đây ns-3 bản phát hành, Bake đã được đưa vào tarball phát hành. Cấu hình
tệp có trong phiên bản đã phát hành sẽ cho phép người ta tải xuống bất kỳ phần mềm nào đã
hiện tại tại thời điểm phát hành. Đó là, ví dụ, phiên bản của Bake là
phân phối với ns-3.21 bản phát hành có thể được sử dụng để tìm nạp các thành phần cho điều đó ns-3 phát hành
hoặc sớm hơn, nhưng không thể được sử dụng để tìm nạp các thành phần cho các bản phát hành sau (trừ khi
nướngconf.xml tệp được cập nhật).

Bạn cũng có thể nhận được bản sao gần đây nhất của nướng bằng cách nhập nội dung sau vào Linux của bạn
shell (giả sử bạn đã cài đặt Mercurial):

$ cd
không gian làm việc $ mkdir
không gian làm việc $ cd
$ hg nhân bản http://code.nsnam.org/bake

Khi lệnh hg (Mercurial) thực thi, bạn sẽ thấy một cái gì đó như sau
hiển thị,

...
thư mục đích: baking
yêu cầu tất cả các thay đổi
thêm các bộ thay đổi
thêm tệp kê khai
thêm các thay đổi tệp
đã thêm 339 tập thay đổi với 796 thay đổi vào 63 tệp
cập nhật lên mặc định chi nhánh
45 tệp được cập nhật, 0 tệp đã hợp nhất, 0 tệp bị xóa, 0 tệp chưa được giải quyết

Sau khi lệnh sao chép hoàn tất, bạn sẽ có một thư mục được gọi là nướng, Nội dung
trong số đó sẽ trông giống như sau:

$ls
nướng bakeconf.xml doc create-binary.py VIỆC CẦN LÀM
thử nghiệm các ví dụ về baking.py

Lưu ý rằng bạn thực sự vừa tải xuống một số tập lệnh Python và một mô-đun Python được gọi là
nướng. Bước tiếp theo sẽ là sử dụng các tập lệnh đó để tải xuống và xây dựng ns-3
phân phối của sự lựa chọn của bạn.

Có một số mục tiêu cấu hình có sẵn:

1. ns-3.22: mô-đun tương ứng với bản phát hành; nó sẽ tải xuống các thành phần tương tự
để phát hành tarball.

2. ns-3-dev: một mô-đun tương tự nhưng sử dụng cây mã phát triển

3. ns-allinone-3.22: mô-đun bao gồm các tính năng tùy chọn khác như nhấp chuột
định tuyến, luồng mở cho ns-3và Nôi mô phỏng mạng

4. ns-3-allinone: tương tự như phiên bản đã phát hành của mô-đun allinone, nhưng dành cho
mã phát triển.

Ảnh chụp nhanh phát triển hiện tại (chưa được phát hành) của ns-3 có thể được tìm thấy tại
http://code.nsnam.org/ns-3-dev/. Các nhà phát triển cố gắng giữ các kho lưu trữ này trong
trạng thái nhất quán, hoạt động nhưng chúng đang ở trong một khu vực phát triển với mã chưa được phát hành
hiện tại, vì vậy bạn có thể muốn xem xét ở lại với bản phát hành chính thức nếu bạn không cần
các tính năng mới được giới thiệu.

Bạn có thể tìm thấy phiên bản mới nhất của mã bằng cách kiểm tra danh sách kho lưu trữ
hoặc bằng cách đi đến "ns-3 Bản phát hành " trang web và nhấp vào liên kết phát hành mới nhất.
Chúng tôi sẽ tiếp tục trong ví dụ hướng dẫn này với ns-3.22.

Bây giờ chúng ta sẽ sử dụng công cụ nướng để kéo các miếng khác nhau của ns-3 bạn sẽ là
đang sử dụng. Đầu tiên, chúng ta sẽ nói một từ về việc chạy nướng.

Bake hoạt động bằng cách tải xuống các gói nguồn vào một thư mục nguồn và cài đặt
thư viện thành một thư mục xây dựng. Bake có thể được chạy bằng cách tham chiếu đến hệ nhị phân, nhưng nếu một
chọn chạy baking từ bên ngoài thư mục mà nó đã được tải xuống, nó được khuyến khích
để đưa ba vào đường dẫn của bạn, chẳng hạn như sau (ví dụ về trình bao bash của Linux). Đầu tiên, hãy thay đổi
vào thư mục 'cook', rồi đặt các biến môi trường sau

$ export BAKE_HOME = `pwd`
$ export PATH = $ PATH: $ BAKE_HOME: $ BAKE_HOME / build / bin
$ export PYTHONPATH = $ PYTHONPATH: $ BAKE_HOME: $ BAKE_HOME / build / lib

Thao tác này sẽ đưa chương trình Bake.py vào đường dẫn của trình bao và cho phép các chương trình khác
tìm các tệp thực thi và thư viện được tạo bởi Bake. Mặc dù một số trường hợp sử dụng bánh nướng không
yêu cầu thiết lập PATH và PYTHONPATH như trên, các bản dựng đầy đủ của ns-3-allinone (với
gói tùy chọn) thường làm.

Bước vào thư mục không gian làm việc và nhập nội dung sau vào trình bao của bạn:

$ ./bake.py cấu hình -e ns-3.22

Tiếp theo, chúng tôi sẽ yêu cầu Bake kiểm tra xem chúng tôi có đủ công cụ để tải xuống các thành phần khác nhau hay không.
Kiểu:

$ ./bake.py kiểm tra

Bạn sẽ thấy một cái gì đó như sau,

> Python - OK
> Trình biên dịch GNU C ++ - OK
> Mercurial - OK
> CVS - OK
> GIT - OK
> Bazaar - OK
> Công cụ Tar - OK
> Công cụ giải nén - OK
> Unrar tool - bị thiếu
> Tiện ích nén dữ liệu 7z - OK
> Tiện ích nén dữ liệu XZ - OK
> Thực hiện - OK
> cMake - OK
> công cụ vá - OK
> công cụ autoreconf - OK

> Đường dẫn tìm kiếm công cụ: /usr/lib64/qt-3.3/bin / usr / lib64 / ccache
/ usr / local / bin / thùng rác / usr / bin / usr / local / sbin / usr / sbin / sbin
/ home / tomh / bin bin

Đặc biệt, các công cụ tải xuống như Mercurial, CVS, GIT và Bazaar là chính của chúng tôi
mối quan tâm tại thời điểm này, vì chúng cho phép chúng tôi tìm nạp mã. Vui lòng cài đặt còn thiếu
ở giai đoạn này, theo cách thông thường cho hệ thống của bạn (nếu bạn có thể), hoặc liên hệ
quản trị viên hệ thống của bạn nếu cần để cài đặt các công cụ này.

Tiếp theo, hãy thử tải xuống phần mềm:

$ ./bake.py tải xuống

nên mang lại một cái gì đó như:

>> Tìm kiếm pygoocanvas phụ thuộc hệ thống - OK
>> Tìm kiếm python-dev phụ thuộc hệ thống - OK
>> Tìm kiếm pygraphviz phụ thuộc hệ thống - OK
>> Tải xuống pybindgen-0.16.0.886 - OK
>> Tìm kiếm phụ thuộc hệ thống g ++ - OK
>> Tìm kiếm phụ thuộc hệ thống qt4 - OK
>> Đang tải xuống netanim-3.105 - OK
>> Đang tải xuống ns-3.22 - OK

Ở trên gợi ý rằng ba nguồn đã được tải xuống. Kiểm tra nguồn thư mục
bây giờ và gõ ls; người ta nên xem:

$ls
netanim-3.105 ns-3.22 pybindgen-0.16.0.886

Bây giờ bạn đã sẵn sàng để xây dựng ns-3 phân phối.

Xây dựng ns-3
Xây dựng với build.py
Khi làm việc từ một tarball đã phát hành, lần đầu tiên bạn xây dựng ns-3 dự án bạn có thể
xây dựng bằng cách sử dụng một chương trình tiện lợi được tìm thấy trong tất cả trong một danh mục. Chương trình này được gọi là
build.py. Chương trình này sẽ cấu hình dự án cho bạn theo cách phổ biến nhất
Cách hữu ích. Tuy nhiên, xin lưu ý rằng cấu hình nâng cao hơn và hoạt động với ns-3 sẽ
thường liên quan đến việc sử dụng bản gốc ns-3 xây dựng hệ thống, Waf, sẽ được giới thiệu sau này
hướng dẫn.

Nếu bạn đã tải xuống bằng tarball, bạn sẽ có một thư mục có tên là
ns-allinone-3.22 dưới của bạn ~ / không gian làm việc danh mục. Nhập nội dung sau:

$ ./build.py --enable -amples --enable-tests

Bởi vì chúng tôi đang làm việc với các ví dụ và thử nghiệm trong hướng dẫn này và vì chúng không
được xây dựng theo mặc định trong ns-3, các đối số cho build.py yêu cầu nó xây dựng chúng cho chúng tôi. Các
chương trình cũng mặc định xây dựng tất cả các mô-đun có sẵn. Sau này, bạn có thể xây dựng ns-3
không có ví dụ và thử nghiệm, hoặc loại bỏ các mô-đun không cần thiết cho công việc của bạn,
nếu bạn ước.

Bạn sẽ thấy rất nhiều thông báo đầu ra của trình biên dịch điển hình được hiển thị khi các bản dựng tập lệnh xây dựng
các phần khác nhau mà bạn đã tải xuống. Cuối cùng, bạn sẽ thấy những điều sau:

Waf: Rời khỏi thư mục `/path/to/workspace/ns-allinone-3.22/ns-3.22/build '
'xây dựng' đã hoàn thành thành công (6 phút 25.032 giây)

Các mô-đun được xây dựng:
ứng dụng anten aodv
cửa hàng cấu hình tòa nhà cầu
cốt lõi csma csma-layout
dsdv dsr năng lượng
internet giám sát luồng thiết bị fd-net
lưới lr-wpan lte
mpi netanim di động (không có Python)
mạng nix-vector-định tuyến olsr
điểm-điểm-điểm-điểm-bố cục
số liệu thống kê phổ sáu thấp
kiểm tra cầu chạm (không có Python) cấu trúc liên kết-đọc
sóng thiết bị mạng ảo uan
wifi

Mô-đun không được xây dựng (xem hướng dẫn ns-3 để giải thích):
quy trình mở nhấp chuột brite
visualizer

Rời khỏi thư mục `./ns-3.22 '

Về phần về các mô-đun không được xây dựng:

Mô-đun không được xây dựng (xem hướng dẫn ns-3 để giải thích):
quy trình mở nhấp chuột brite
visualizer

Điều này chỉ có nghĩa là một số ns-3 các mô-đun có sự phụ thuộc vào các thư viện bên ngoài có thể không
đã được xây dựng hoặc cấu hình được yêu cầu cụ thể không xây dựng chúng. Nó có
không có nghĩa là trình mô phỏng không tạo thành công hoặc nó sẽ cung cấp sai
kết quả cho các mô-đun được liệt kê là đã được xây dựng.

Xây dựng với nướng
Nếu bạn đã sử dụng Bake ở trên để tìm nạp mã nguồn từ kho dự án, bạn có thể tiếp tục
sử dụng nó để xây dựng ns-3. Kiểu

$ ./bake.py xây dựng

và bạn sẽ thấy một cái gì đó như:

>> Xây dựng pybindgen-0.16.0.886 - OK
>> Xây dựng netanim-3.105 - OK
>> Tòa nhà ns-3.22 - OK

Dấu: bạn có thể Ngoài ra thực hiện cả hai các bước, tải về xây dựng by gọi 'baking.py triển khai'.

Nếu xảy ra lỗi, hãy xem lệnh sau cho biết gì
bạn; nó có thể đưa ra gợi ý về sự phụ thuộc bị thiếu:

$ ./bake.py hiển thị

Điều này sẽ liệt kê ra các phụ thuộc khác nhau của các gói mà bạn đang cố gắng xây dựng.

Xây dựng với Waf
Cho đến thời điểm này, chúng tôi đã sử dụng build.py script, hoặc nướng công cụ, để có được
bắt đầu với việc xây dựng ns-3. Những công cụ này rất hữu ích cho việc xây dựng ns-3 và hỗ trợ
thư viện và họ gọi vào ns-3 thư mục để gọi công cụ xây dựng Waf để thực hiện
tòa nhà thực tế. Hầu hết người dùng nhanh chóng chuyển sang sử dụng trực tiếp Waf để cấu hình và
xây dựng ns-3. Vì vậy, để tiếp tục, vui lòng thay đổi thư mục làm việc của bạn thành ns-3 thư mục
mà bạn đã xây dựng ban đầu.

Nó không được yêu cầu nghiêm ngặt vào thời điểm này, nhưng sẽ có giá trị nếu đi đường vòng một chút
và xem cách thực hiện các thay đổi đối với cấu hình của dự án. Có lẽ là nhiều nhất
thay đổi cấu hình hữu ích mà bạn có thể thực hiện để xây dựng phiên bản được tối ưu hóa của
mã số. Theo mặc định, bạn đã định cấu hình dự án của mình để tạo phiên bản gỡ lỗi. Hay cho biêt
dự án để tạo một bản dựng được tối ưu hóa. Để giải thích cho Waf rằng nó phải được tối ưu hóa
các bản dựng bao gồm các ví dụ và bài kiểm tra, bạn sẽ cần thực hiện những điều sau
lệnh:

$ ./waf sạch sẽ
$ ./waf --build-profile = tối ưu hóa --enable -amples --enable-tests config

Điều này chạy Waf ra khỏi thư mục cục bộ (được cung cấp để tạo sự thuận tiện cho bạn).
Lệnh đầu tiên để xóa bản dựng trước đó thường không hoàn toàn cần thiết nhưng
là thực hành tốt (nhưng hãy xem Xây dựng Profiles, phía dưới); nó sẽ loại bỏ những thứ đã xây dựng trước đó
thư viện và tệp đối tượng được tìm thấy trong thư mục xây dựng/. Khi dự án được cấu hình lại
và hệ thống xây dựng kiểm tra các phụ thuộc khác nhau, bạn sẽ thấy kết quả đầu ra
tương tự như sau:

Đặt trên cùng thành:.
Đặt ra: xây dựng
Kiểm tra 'gcc' (trình biên dịch c): / usr / bin / gcc
Kiểm tra phiên bản cc: 4.2.1
Kiểm tra 'g ++' (trình biên dịch c ++): / usr / bin / g ++
Kiểm tra tăng cường bao gồm: 1_46_1
Kiểm tra boost libs: ok
Kiểm tra liên kết thúc đẩy: ok
Kiểm tra vị trí nhấp chuột: không tìm thấy
Kiểm tra chương trình pkg-config: / sw / bin / pkg-config
Kiểm tra 'gtk + -2.0'> = 2.12: có
Kiểm tra 'libxml-2.0'> = 2.7: yes
Kiểm tra loại uint128_t: không tìm thấy
Kiểm tra loại __uint128_t: yes
Kiểm tra việc triển khai độ chính xác cao: số nguyên 128 bit (mặc định)
Kiểm tra tiêu đề stdint.h: yes
Kiểm tra tiêu đề inttypes.h: yes
Kiểm tra tiêu đề sys / inttypes.h: không tìm thấy
Kiểm tra sys / type tiêu đề. H: yes
Kiểm tra hệ thống tiêu đề / stat.h: có
Kiểm tra tiêu đề chỉ thị.h: có
Kiểm tra tiêu đề stdlib.h: có
Kiểm tra tín hiệu tiêu đề.h: yes
Kiểm tra tiêu đề pthread.h: có
Kiểm tra tiêu đề stdint.h: yes
Kiểm tra tiêu đề inttypes.h: yes
Kiểm tra tiêu đề sys / inttypes.h: không tìm thấy
Kiểm tra thư viện rt: không tìm thấy
Kiểm tra tiêu đề netpacket / pack.h: không tìm thấy
Kiểm tra tiêu đề sys / ioctl.h: yes
Kiểm tra tiêu đề net / if.h: không tìm thấy
Kiểm tra tiêu đề net / ethernet.h: có
Kiểm tra tiêu đề linux / if_tun.h: không tìm thấy
Kiểm tra tiêu đề netpacket / pack.h: không tìm thấy
Kiểm tra vị trí NSC: không tìm thấy
Kiểm tra 'mpic ++': có
Kiểm tra 'sqlite3': có
Kiểm tra tiêu đề linux / if_tun.h: không tìm thấy
Kiểm tra chương trình sudo: / usr / bin / sudo
Kiểm tra giá trị chương trình: / sw / bin / valgrind
Kiểm tra 'gsl': có
Kiểm tra cờ biên dịch -Wno-error = bị phản đối-d ... support: ok
Kiểm tra cờ biên dịch -Wno-error = bị phản đối-d ... support: ok
Kiểm tra cờ biên dịch -fstrict-aliasing ... support: ok
Kiểm tra cờ biên dịch -fstrict-aliasing ... support: ok
Kiểm tra cờ biên dịch -giá răng cưa ... hỗ trợ: ok
Kiểm tra cờ biên dịch -giá răng cưa ... hỗ trợ: ok
Kiểm tra doxygen của chương trình: / usr / local / bin / doxygen
---- Tóm tắt các tính năng NS-3 tùy chọn:
Xây dựng hồ sơ: gỡ lỗi
Thư mục xây dựng: xây dựng
Python Bindings: đã bật
Tích hợp BRITE: chưa được bật (BRITE chưa được bật (xem tùy chọn --with-brite))
Tích hợp nhấp chuột NS-3: chưa được bật (nsclick chưa được bật (xem tùy chọn --with-nsclick))
GtkConfigStore: đã bật
XmlIo: đã bật
Nguyên thủy phân luồng: đã bật
Trình mô phỏng thời gian thực: được bật (librt không khả dụng)
Thiết bị mạng được mô phỏng: đã bật ( bao gồm không được phát hiện)
Bộ mô tả tệp NetDevice: đã bật
Nhấn vào FdNetDevice: không được bật (cần linux / if_tun.h)
Giả lập FdNetDevice: không được bật (cần netpacket / pack.h)
PlanetLab FdNetDevice: không được bật (không phát hiện thấy hệ điều hành PlanetLab (xem tùy chọn --force-Planetlab))
Network Simulation Cradle: không được bật (Không tìm thấy NSC (xem tùy chọn --with-nsc))
Hỗ trợ MPI: đã bật
NS-3 OpenFlow Integration: không được bật (Không tìm thấy thư viện tăng cường bắt buộc, thiếu: hệ thống, tín hiệu, hệ thống tệp)
Đầu ra dữ liệu thống kê SQlite: đã bật
Chạm vào Cầu: chưa được bật ( bao gồm không được phát hiện)
Trình hiển thị PyViz: đã bật
Sử dụng sudo để đặt bit suid: không được bật (tùy chọn --enable-sudo không được chọn)
Thử nghiệm xây dựng: đã bật
Xây dựng ví dụ: đã bật
Thư viện Khoa học GNU (GSL): đã bật
'config' đã hoàn tất thành công (1.944 giây)

Lưu ý phần cuối cùng của đầu ra ở trên. Một vài ns-3 các tùy chọn không được bật theo mặc định hoặc
yêu cầu hỗ trợ từ hệ thống bên dưới để hoạt động bình thường. Ví dụ, để kích hoạt
XmlTo, thư viện libxml-2.0 phải được tìm thấy trên hệ thống. Nếu thư viện này không
tìm thấy, tương ứng ns-3 tính năng sẽ không được kích hoạt và một thông báo sẽ là
hiển thị. Lưu ý thêm rằng có một tính năng để sử dụng chương trình sudo để đặt suid
bit của một số chương trình nhất định. Tính năng này không được bật theo mặc định và do đó tính năng này được báo cáo
là "chưa được kích hoạt."

Bây giờ, hãy tiếp tục và chuyển trở lại bản dựng gỡ lỗi bao gồm các ví dụ và thử nghiệm.

$ ./waf sạch sẽ
$ ./waf --build-profile = debug --enable -amples --enable-tests config

Hệ thống xây dựng hiện đã được định cấu hình và bạn có thể tạo các phiên bản gỡ lỗi của ns-3
chương trình chỉ bằng cách gõ

$ ./waf

Được rồi, xin lỗi, tôi đã yêu cầu bạn xây dựng ns-3 một phần của hệ thống hai lần, nhưng bây giờ bạn biết cách
thay đổi cấu hình và xây dựng mã tối ưu hóa.

Tập lệnh build.py được thảo luận ở trên cũng hỗ trợ --enable-ví dụphép thử nghiệm
các đối số, nhưng nói chung, không hỗ trợ trực tiếp các tùy chọn waf khác; ví dụ, cái này
sẽ không làm việc:

$ ./build.py --disable-python

sẽ cho kết quả

build.py: error: không có tùy chọn như vậy: --disable-python

Tuy nhiên, nhà điều hành đặc biệt -- có thể được sử dụng để chuyển các tùy chọn bổ sung đến waf, vì vậy
thay vì những điều trên, những điều sau sẽ hoạt động:

$ ./build.py - --disable-python

vì nó tạo ra lệnh cơ bản ./waff cấu hình --disable-python.

Dưới đây là một số mẹo giới thiệu thêm về Waf.

Thiết lập vs. Xây dựng
Một số lệnh Waf chỉ có ý nghĩa trong giai đoạn cấu hình và một số lệnh
hợp lệ trong giai đoạn xây dựng. Ví dụ: nếu bạn muốn sử dụng các tính năng mô phỏng của
ns-3, bạn có thể muốn bật cài đặt bit suid bằng cách sử dụng sudo như được mô tả ở trên. Cái này
hóa ra là một lệnh cấu hình thời gian và vì vậy bạn có thể định cấu hình lại bằng cách sử dụng
lệnh sau cũng bao gồm các ví dụ và thử nghiệm.

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

Nếu bạn làm điều này, Waf sẽ chạy sudo để thay đổi các chương trình tạo socket của
mã mô phỏng để chạy dưới dạng root.

Có nhiều tùy chọn cấu hình và thời gian xây dựng khác có sẵn trong Waf. Để khám phá những
tùy chọn, loại:

$ ./waf --help

Chúng tôi sẽ sử dụng một số lệnh liên quan đến thử nghiệm trong phần tiếp theo.

Xây dựng Profiles
Chúng tôi đã biết cách bạn có thể định cấu hình Waf cho gỡ lỗi or tối ưu hóa xây dựng:

$ ./waf --build-profile = debug

Ngoài ra còn có một hồ sơ xây dựng trung gian, phát hành. -d là một từ đồng nghĩa với
- xây dựng hồ sơ.

Theo mặc định, Waf đặt các tạo tác xây dựng trong xây dựng danh mục. Bạn có thể chỉ định một
thư mục đầu ra khác với --ngoài tùy chọn, ví dụ

$ ./waf configure --out = foo

Kết hợp điều này với cấu hình xây dựng cho phép bạn chuyển đổi giữa các tùy chọn biên dịch khác nhau
một cách rõ ràng:

$ ./waf config --build-profile = debug --out = build / debug
$ ./waf bản dựng
...
$ ./waf configure --build-profile = Optimizer --out = build / tối ưu hóa
$ ./waf bản dựng
...

Điều này cho phép bạn làm việc với nhiều bản dựng thay vì luôn ghi đè lên bản cuối cùng
xây dựng. Khi bạn chuyển đổi, Waf sẽ chỉ biên dịch những gì nó cần, thay vì biên dịch lại
tất cả mọi thứ.

Khi bạn chuyển đổi các cấu hình xây dựng như thế này, bạn phải cẩn thận để cung cấp
các thông số cấu hình mỗi lần. Có thể thuận tiện để xác định một số môi trường
các biến để giúp bạn tránh những sai lầm:

$ export NS3CONFIG = "- enable -amples --enable-tests"
$ export NS3DEBUG = "- build-profile = debug --out = build / debug"
$ export NS3OPT == "- build-profile = Optimizer --out = build / Optimizer"

$ ./waf cấu hình $ NS3CONFIG $ NS3DEBUG
$ ./waf bản dựng
...
$ ./waf cấu hình $ NS3CONFIG $ NS3OPT
$ ./waf bản dựng

Trình biên dịch
Trong các ví dụ trên, Waf sử dụng trình biên dịch GCC C ++, g ++, để xây dựng ns-3. Tuy nhiên,
có thể thay đổi trình biên dịch C ++ được Waf sử dụng bằng cách xác định CXX môi trường
Biến đổi. Ví dụ, để sử dụng trình biên dịch Clang C ++, leng keng ++,

$ CXX = "clang ++" ./waf cấu hình
$ ./waf bản dựng

Người ta cũng có thể thiết lập Waf để thực hiện biên dịch phân tán với ditcc theo cách tương tự:

$ CXX = "distcc g ++" ./waf config
$ ./waf bản dựng

Thông tin thêm về ditcc và biên dịch phân tán có thể được tìm thấy trên nó dự án trang Dưới
Phần tài liệu.

đặt
Waf có thể được sử dụng để cài đặt các thư viện ở nhiều nơi khác nhau trên hệ thống. Mặc định
vị trí nơi thư viện và tệp thực thi được xây dựng trong xây dựng thư mục, và bởi vì
Waf biết vị trí của các thư viện và tệp thực thi này, không cần thiết phải cài đặt
các thư viện ở nơi khác.

Nếu người dùng chọn cài đặt những thứ bên ngoài thư mục bản dựng, người dùng có thể phát hành
./waff cài đặt, dựng lên chỉ huy. Theo mặc định, tiền tố để cài đặt là / usr / local, Vì vậy ./waff
cài đặt, dựng lên sẽ cài đặt các chương trình vào / usr / local / bin, thư viện thành / Usr / local / lib
tiêu đề vào / usr / local / bao gồm. Đặc quyền siêu người dùng thường cần thiết để cài đặt
tiền tố mặc định, vì vậy lệnh điển hình sẽ là sudo ./waff cài đặt, dựng lên. Khi chạy
chương trình với Waf, trước tiên Waf sẽ thích sử dụng các thư viện được chia sẻ trong thư mục xây dựng,
sau đó sẽ tìm kiếm các thư viện trong đường dẫn thư viện được cấu hình trong môi trường cục bộ. Vì thế
khi cài đặt các thư viện vào hệ thống, bạn nên kiểm tra xem mục đích
thư viện đang được sử dụng.

Người dùng có thể chọn cài đặt đến một tiền tố khác bằng cách chuyển --tiếp đầu ngữ tùy chọn tại
định cấu hình thời gian, chẳng hạn như:

./waf config --prefix = / opt / local

Nếu sau đó sau khi xây dựng, người dùng vấn đề ./waff cài đặt, dựng lên lệnh, tiền tố / opt / local
sẽ được sử dụng.

Sản phẩm ./waff giống cá lăng lệnh nên được sử dụng trước khi cấu hình lại dự án nếu Waf sẽ
được sử dụng để cài đặt mọi thứ ở một tiền tố khác.

Tóm lại là không cần thiết phải gọi ./waff cài đặt, dựng lên sử dụng ns-3. Hầu hết người dùng sẽ không
cần lệnh này vì Waf sẽ chọn các thư viện hiện tại từ xây dựng danh mục,
nhưng một số người dùng có thể thấy hữu ích nếu trường hợp sử dụng của họ liên quan đến việc làm việc với các chương trình bên ngoài
của ns-3 thư mục.

Một Waf
Chỉ có một tập lệnh Waf, ở cấp cao nhất của ns-3 cây nguồn. Khi bạn làm việc, bạn
có thể thấy mình dành nhiều thời gian cho vết trầy/, hoặc sâu trong src / ...và cần phải
gọi Waf. Bạn chỉ có thể nhớ mình đang ở đâu và gọi Waf như thế này:

$../../../waf...

nhưng điều đó trở nên tẻ nhạt và dễ xảy ra lỗi, và có những giải pháp tốt hơn.

Nếu bạn có đầy đủ ns-3 kho lưu trữ viên ngọc nhỏ này là một khởi đầu:

$ cd $ (hg root) && ./waf ...

Tốt hơn nữa là định nghĩa đây là một hàm shell:

$ function waff {cd $ (hg root) && ./waf $ *; }

bản dựng $ waff

Nếu bạn chỉ có tarball, một biến môi trường có thể giúp:

$ export NS3DIR = "$ PWD"
$ function waff {cd $ NS3DIR && ./waf $ *; }

$ cd cào
bản dựng $ waff

Nó có thể được cám dỗ trong một thư mục mô-đun để thêm một WAF script dọc theo dòng của
giám đốc điều hành ../../waf. Xin đừng. Nó gây nhầm lẫn cho những người mới đến và khi thực hiện nó kém
dẫn đến lỗi xây dựng tinh vi. Các giải pháp trên là con đường để đi.

Kiểm tra ns-3
Bạn có thể chạy các bài kiểm tra đơn vị của ns-3 phân phối bằng cách chạy ./test.py -c cốt lõi
kịch bản:

lõi $ ./test.py -c

Các bài kiểm tra này được Waf chạy song song. Cuối cùng bạn sẽ thấy một báo cáo nói rằng

92 trong số 92 bài kiểm tra đã vượt qua (92 bài đạt, 0 bài không đạt, 0 bài bị lỗi, 0 lỗi giá trị)

Đây là thông điệp quan trọng.

Bạn cũng sẽ thấy kết quả tóm tắt từ Waf và trình chạy thử nghiệm thực hiện mỗi thử nghiệm,
mà thực sự sẽ trông giống như sau:

Waf: Nhập thư mục `/ path / to / workspace / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ path / to / workspace / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (1.799 giây)

Các mô-đun được xây dựng:
cầu nối các ứng dụng aodv
nhấp vào lõi lưu trữ cấu hình
dsdv bố cục csma csma
giám sát dòng chảy năng lượng emu
lưới internet
mpi netanim di động
mạng nix-vector-routing ns3tcp
quy trình mở ns3wifi olsr
điểm-điểm-điểm-điểm-bố cục
thống kê quang phổ tap-bridge
công cụ kiểm tra mẫu
cấu trúc liên kết-đọc uan virtual-net-device
Visualizer wifi wimax

PASS: TestSuite ns3-wifi-can thiệp
PASS: Biểu đồ TestSuite

...

PASS: Đối tượng TestSuite
PASS: Bộ tạo số ngẫu nhiên TestSuite
92 trong số 92 bài kiểm tra đã vượt qua (92 bài đạt, 0 bài không đạt, 0 bài bị lỗi, 0 lỗi giá trị)

Lệnh này thường được chạy bởi người dùng để nhanh chóng xác minh rằng một ns-3 phân phối có
được xây dựng một cách chính xác. (Lưu ý thứ tự của ĐI QUA: ... dòng có thể khác nhau, điều này không sao cả. Cái gì
quan trọng là dòng tóm tắt ở cuối báo cáo rằng tất cả các bài kiểm tra đã vượt qua; không có thất bại hoặc
bị rơi.)

Chạy a Script
Chúng tôi thường chạy các tập lệnh dưới sự kiểm soát của Waf. Điều này cho phép hệ thống xây dựng đảm bảo
rằng các đường dẫn thư viện được chia sẻ được đặt chính xác và các thư viện có sẵn tại
thời gian chạy. Để chạy một chương trình, chỉ cần sử dụng --chạy tùy chọn trong Waf. Hãy chạy ns-3
tương đương với chương trình hello world phổ biến bằng cách nhập như sau:

$ ./waf --run xin chào-giả lập

Trước tiên, Waf sẽ kiểm tra để đảm bảo rằng chương trình được xây dựng đúng cách và thực hiện một bản dựng nếu
yêu cầu. Waf sau đó thực thi chương trình, tạo ra kết quả sau.

Xin chào Trình mô phỏng

Xin chúc mừng! Bạn hiện là người dùng ns-3!

Điều gì do I do if I không xem các sản lượng?

Nếu bạn thấy thông báo Waf cho biết rằng quá trình xây dựng đã hoàn tất thành công, nhưng không
xem đầu ra "Hello Simulator", rất có thể bạn đã chuyển chế độ xây dựng của mình sang
tối ưu hóa trong Xây dựng với Waf nhưng đã bỏ lỡ thay đổi trở lại gỡ lỗi chế độ.
Tất cả đầu ra bảng điều khiển được sử dụng trong hướng dẫn này sử dụng ns-3 thành phần ghi nhật ký mà
rất hữu ích để in thông báo của người dùng vào bảng điều khiển. Đầu ra từ thành phần này là
tự động bị vô hiệu hóa khi bạn biên dịch mã được tối ưu hóa - nó được "tối ưu hóa". nếu bạn
không thấy đầu ra "Hello Simulator", hãy nhập như sau:

$ ./waf configure --build-profile = debug --enable -amples --enable-tests

để yêu cầu Waf xây dựng các phiên bản gỡ lỗi của ns-3 chương trình bao gồm các ví dụ
và các bài kiểm tra. Bạn vẫn phải tạo phiên bản gỡ lỗi thực tế của mã bằng cách nhập

$ ./waf

Bây giờ, nếu bạn chạy xin chào-mô phỏng chương trình, bạn sẽ thấy kết quả mong đợi.

chương trình Lập luận
Để cung cấp các đối số dòng lệnh cho một ns-3 chương trình sử dụng mẫu này:

$ ./waf --run --command-template = "% s "

Thay thế tên chương trình của bạn cho và các đối số cho . Các
--mẫu lệnh đối số với Waf về cơ bản là một công thức để xây dựng
dòng lệnh Waf nên sử dụng để thực thi chương trình. Waf kiểm tra xem bản dựng có
hoàn thành, đặt các đường dẫn thư viện được chia sẻ, sau đó gọi tệp thực thi bằng cách sử dụng
mẫu dòng lệnh, chèn tên chương trình cho %s trình giữ chỗ. (Tôi thừa nhận điều này
hơi khó xử, nhưng đó là cách của nó. Các bản vá lỗi được chào đón!)

Một ví dụ đặc biệt hữu ích khác là tự chạy một bộ thử nghiệm. Hãy giả sử rằng một
bí ẩn nhất bộ thử nghiệm tồn tại (nó không). Ở trên, chúng tôi đã sử dụng ./test.py script để chạy toàn bộ
hàng loạt thử nghiệm song song, bằng cách liên tục gọi chương trình thử nghiệm thực, người chạy thử nghiệm.
Để gọi người chạy thử nghiệm trực tiếp cho một bài kiểm tra duy nhất:

$ ./waf --run test-runner --command-template = "% s --suite = mytest --verbose"

Điều này chuyển các đối số cho người chạy thử nghiệm chương trình. Từ bí ẩn nhất không tồn tại, một
thông báo lỗi sẽ được tạo. Để in cái có sẵn người chạy thử nghiệm lựa chọn:

$ ./waf --run test-runner --command-template = "% s --help"

Gỡ lỗi
Chạy ns-3 các chương trình dưới sự kiểm soát của một tiện ích khác, chẳng hạn như trình gỡ lỗi (ví dụ gdb)
hoặc trình kiểm tra bộ nhớ (ví dụ valgrind), bạn sử dụng một --command-template = "..." hình thức.

Ví dụ, để chạy ns-3 chương trình xin chào-mô phỏng với các đối số theo
gdb trình gỡ lỗi:

$ ./waf --run = hello-simulator --command-template = "gdb% s --args "

Chú ý rằng ns-3 tên chương trình đi với --chạy đối số và tiện ích điều khiển
(đây gdb) là mã thông báo đầu tiên trong --mẫu lệnh tranh luận. Các --args nói gdb
rằng phần còn lại của dòng lệnh thuộc về chương trình "thấp hơn". (Một vài gdb's
không hiểu --args đặc tính. Trong trường hợp này, hãy bỏ qua các đối số của chương trình khỏi
--mẫu lệnh, và sử dụng gdb lệnh định args..)

Chúng tôi có thể kết hợp công thức này và công thức trước đó để chạy thử nghiệm trong trình gỡ lỗi:

$ ./waf --run test-runner --command-template = "gdb% s --args --suite = mytest --verbose"

Đang làm việc thư mục
Waf cần phải chạy từ vị trí của nó ở đầu ns-3 cây. Điều này trở thành công việc
thư mục nơi các tập tin đầu ra sẽ được ghi. Nhưng điều gì sẽ xảy ra nếu bạn muốn giữ những người yêu thích đó
các ns-3 cây nguồn? Sử dụng --cwd tranh luận:

$ ./waf --cwd = ...

Có thể thuận tiện hơn khi bắt đầu với thư mục làm việc của bạn nơi bạn muốn đầu ra
các tệp, trong trường hợp đó, một chút chuyển hướng có thể giúp:

$ hàm waff {
CWD = "$ PWD"
cd $ NS3DIR> / dev / null
./waf --cwd = "$ CWD" $ *
cd -> / dev / null
}

Sự bổ sung này của phiên bản trước lưu thư mục làm việc hiện tại, cdlà để
thư mục Waf, sau đó hướng dẫn Waf thay đổi thư mục làm việc trở lại để lưu
thư mục làm việc hiện tại trước khi chạy chương trình.

KHÁI NIỆM TỔNG QUAN


Điều đầu tiên chúng ta cần làm trước khi thực sự bắt đầu xem hoặc viết ns-3 mã là
giải thích một vài khái niệm cốt lõi và những điều trừu tượng trong hệ thống. Phần lớn điều này có thể xuất hiện
rõ ràng một cách rõ ràng đối với một số người, nhưng chúng tôi khuyên bạn nên dành thời gian để đọc qua phần này
chỉ để đảm bảo bạn đang bắt đầu trên một nền tảng vững chắc.

Key Trừu tượng
Trong phần này, chúng tôi sẽ xem xét một số thuật ngữ thường được sử dụng trong mạng, nhưng có
ý nghĩa cụ thể trong ns-3.

Node
Theo thuật ngữ Internet, một thiết bị máy tính kết nối với mạng được gọi là chủ nhà or
đôi khi một cuối hệ thống. Bởi vì ns-3 là một mạng trình mô phỏng, không cụ thể là một
Internet giả lập, chúng tôi cố ý không sử dụng cụm từ máy chủ lưu trữ vì nó gần giống
liên kết với Internet và các giao thức của nó. Thay vào đó, chúng tôi sử dụng một thuật ngữ chung chung hơn cũng
được sử dụng bởi các trình mô phỏng khác bắt nguồn từ Lý thuyết đồ thị --- nút.

In ns-3 phần trừu tượng của thiết bị tính toán cơ bản được gọi là nút. Sự trừu tượng này là
được đại diện trong C ++ bởi lớp Node. Các Node lớp cung cấp các phương thức để quản lý
biểu diễn của các thiết bị tính toán trong mô phỏng.

Bạn nên nghĩ về một Node như một máy tính mà bạn sẽ thêm chức năng. Một người nói thêm
những thứ như ứng dụng, ngăn xếp giao thức và thẻ ngoại vi được liên kết với chúng
trình điều khiển để cho phép máy tính thực hiện công việc hữu ích. Chúng tôi sử dụng cùng một mô hình cơ bản trong ns-3.

Các Ứng Dụng
Thông thường, phần mềm máy tính được chia thành hai lớp lớn. WELFARE Phần mềm tổ chức
các tài nguyên máy tính khác nhau như bộ nhớ, chu trình bộ xử lý, đĩa, mạng, v.v.,
theo một số mô hình tính toán. Phần mềm hệ thống thường không sử dụng các tài nguyên đó
để hoàn thành các tác vụ mang lại lợi ích trực tiếp cho người dùng. Một người dùng thường sẽ chạy một ứng dụng
thu được và sử dụng các tài nguyên được kiểm soát bởi phần mềm hệ thống để thực hiện một số
mục tiêu.

Thông thường, ranh giới tách biệt giữa hệ thống và phần mềm ứng dụng được thực hiện ở
thay đổi mức đặc quyền xảy ra trong các bẫy của hệ điều hành. Trong ns-3 không có thực
khái niệm về hệ điều hành và đặc biệt là không có khái niệm về mức đặc quyền hay lời gọi hệ thống.
Tuy nhiên, chúng tôi có ý tưởng về một ứng dụng. Cũng giống như các ứng dụng phần mềm chạy trên
máy tính để thực hiện các tác vụ trong "thế giới thực" ns-3 ứng dụng chạy trên ns-3 Nodes đến
mô phỏng lái xe trong thế giới mô phỏng.

In ns-3 trừu tượng cơ bản cho một chương trình người dùng tạo ra một số hoạt động
mô phỏng là ứng dụng. Sự trừu tượng này được biểu diễn trong C ++ bởi lớp
Các Ứng Dụng. Các Các Ứng Dụng lớp cung cấp các phương thức để quản lý các biểu diễn của
phiên bản của chúng tôi về các ứng dụng cấp người dùng trong mô phỏng. Các nhà phát triển dự kiến ​​sẽ
chuyên môn hóa Các Ứng Dụng lớp theo nghĩa lập trình hướng đối tượng để tạo mới
các ứng dụng. Trong hướng dẫn này, chúng tôi sẽ sử dụng các chuyên môn của lớp Các Ứng Dụng gọi là
Ứng dụng UdpEchoClientỨng dụng UdpEchoServer. Như bạn có thể mong đợi, những
các ứng dụng soạn một bộ ứng dụng máy khách / máy chủ được sử dụng để tạo và mô phỏng tiếng vọng
gói mạng

Kênh
Trong thế giới thực, người ta có thể kết nối máy tính với mạng. Thường thì các phương tiện truyền thông
luồng dữ liệu trong các mạng này được gọi là kênh. Khi bạn kết nối cáp Ethernet với
cắm trên tường, bạn đang kết nối máy tính của mình với giao tiếp Ethernet
kênh. Trong thế giới mô phỏng của ns-3, một người kết nối một Node đến một đối tượng đại diện cho một
kênh thông tin liên lạc. Ở đây, sự trừu tượng hóa mạng con giao tiếp cơ bản được gọi là
kênh và được đại diện bằng C ++ bởi lớp Kênh.

Sản phẩm Kênh lớp cung cấp các phương thức để quản lý các đối tượng mạng con giao tiếp và
kết nối các nút với chúng. Các kênh cũng có thể được các nhà phát triển chuyên môn hóa trong đối tượng
lập trình định hướng giác quan. MỘT Kênh chuyên môn hóa có thể mô hình hóa một cái gì đó đơn giản như
dây điện. Chuyên ngành Kênh cũng có thể mô hình hóa những thứ phức tạp như một Ethernet lớn
chuyển mạch, hoặc không gian ba chiều đầy vật cản trong trường hợp mạng không dây.

Chúng tôi sẽ sử dụng các phiên bản chuyên biệt của Kênh gọi là CsmaKênh, Điểm Đến ĐiểmKênh
Kênh Wifi trong hướng dẫn này. Các CsmaKênh, ví dụ: mô hình hóa một phiên bản của
mạng con giao tiếp thực hiện một nhà cung cấp dịch vụ ý nghĩa nhiều truy cập thông tin
Trung bình. Điều này cung cấp cho chúng tôi chức năng giống như Ethernet.

Net Dụng cụ
Đã từng xảy ra trường hợp nếu bạn muốn kết nối máy tính với mạng, bạn phải
mua một loại cáp mạng cụ thể và một thiết bị phần cứng được gọi là (theo thuật ngữ PC) a
chu vi thẻ cần được cài đặt trong máy tính của bạn. Nếu thẻ ngoại vi
đã triển khai một số chức năng mạng, chúng được gọi là Thẻ giao diện mạng, hoặc NIC.
Ngày nay, hầu hết các máy tính đều có phần cứng giao diện mạng được tích hợp sẵn và người dùng không thấy
các khối xây dựng này.

NIC sẽ không hoạt động nếu không có trình điều khiển phần mềm để điều khiển phần cứng. Trong Unix (hoặc
Linux), một phần của phần cứng ngoại vi được phân loại là thiết bị. Các thiết bị được kiểm soát
sử dụng thiết bị trình điều khiểnvà các thiết bị mạng (NIC) được điều khiển bằng cách sử dụng mạng thiết bị
trình điều khiển được gọi chung là net thiết bị. Trong Unix và Linux, bạn tham khảo các mạng này
các thiết bị có tên như eth0.

In ns-3 các net thiết bị trừu tượng bao gồm cả trình điều khiển phần mềm và mô phỏng
phần cứng. Một thiết bị mạng được "cài đặt" trong một Node để cho phép Node đến
giao tiếp với người khác Nodes trong mô phỏng thông qua Các kênh. Cũng giống như trong một máy tính thực,
a Node có thể được kết nối với nhiều hơn một Kênh qua nhiều thiết bị mạng.

Phần trừu tượng thiết bị ròng được biểu diễn bằng C ++ bởi lớp thiết bị mạng. Các thiết bị mạng
lớp cung cấp các phương thức để quản lý các kết nối tới NodeKênh các đối tượng; và có thể
được các nhà phát triển chuyên biệt hóa theo nghĩa lập trình hướng đối tượng. Chúng tôi sẽ sử dụng
một số phiên bản chuyên biệt của thiết bị mạng gọi là Thiết bị CsmaNet, PointToPointNetThiết bị,
WifiMạngThiết Bị trong hướng dẫn này. Cũng như Ethernet NIC được thiết kế để hoạt động với
Mạng Ethernet, Thiết bị CsmaNet được thiết kế để làm việc với CsmaKênh; Các
PointToPointNetThiết bị được thiết kế để làm việc với Điểm Đến ĐiểmKênhWifiNetThiết Bị
được thiết kế để làm việc với Kênh Wifi.

topology Người giúp việc
Trong một mạng thực, bạn sẽ tìm thấy các máy tính chủ có NIC được bổ sung (hoặc tích hợp sẵn). Trong ns-3 we
sẽ nói rằng bạn sẽ tìm thấy Nodes có đính kèm thiết bị mạng. Trong một mạng mô phỏng lớn
bạn sẽ cần phải sắp xếp nhiều kết nối giữa Nodes, thiết bị mạngCác kênh.

Kể từ khi kết nối thiết bị mạng đến Nodes, thiết bị mạng đến Các kênh, gán địa chỉ IP,
v.v., là những nhiệm vụ phổ biến như vậy trong ns-3, chúng tôi cung cấp những gì chúng tôi gọi là cấu trúc liên kết người giúp việc để làm điều này
dễ dàng nhất có thể. Ví dụ, nó có thể có nhiều ns-3 hoạt động cốt lõi để
tạo một NetDevice, thêm địa chỉ MAC, cài đặt thiết bị mạng đó trên một Node, cấu hình
ngăn xếp giao thức của nút, và sau đó kết nối thiết bị mạng đến một Kênh. Thậm chí nhiều hoạt động
sẽ được yêu cầu kết nối nhiều thiết bị với các kênh đa điểm và sau đó kết nối
các mạng riêng lẻ với nhau thành các mạng internet. Chúng tôi cung cấp các đối tượng trình trợ giúp cấu trúc liên kết
kết hợp nhiều hoạt động riêng biệt đó thành một mô hình dễ sử dụng để thuận tiện cho bạn.

A Tên ns-3 Script
Nếu bạn đã tải xuống hệ thống như được đề xuất ở trên, bạn sẽ có một bản phát hành ns-3 trong một
thư mục được gọi là còn lại trong thư mục chính của bạn. Thay đổi thư mục phát hành đó và
bạn sẽ tìm thấy một cấu trúc thư mục giống như sau:

AUTHORS ví dụ về cào utils waf.bat *
ràng buộc LICENSE src utils.py waf-tools
build ns3 test.py * utils.pyc wscript
CHANGES.html PHIÊN BẢN đầu ra thử nghiệm README wutils.py
doc RELEASE_NOTES testpy.supp waf * wutils.pyc

Thay đổi thành ví dụ / hướng dẫn danh mục. Bạn sẽ thấy một tệp có tên đầu tiên.cc nằm
ở đó. Đây là một tập lệnh sẽ tạo ra một liên kết điểm-điểm đơn giản giữa hai nút
và lặp lại một gói duy nhất giữa các nút. Hãy xem qua dòng kịch bản đó bằng cách
dòng, vì vậy hãy tiếp tục và mở đầu tiên.cc trong trình soạn thảo yêu thích của bạn.

bản mẫu
Dòng đầu tiên trong tệp là dòng chế độ emacs. Điều này cho emac biết về định dạng
quy ước (kiểu mã hóa) mà chúng tôi sử dụng trong mã nguồn của mình.

/ * - * - Chế độ: C ++; c-file-style: "gnu"; thụt lề-tabs-mode: nil; - * - * /

Đây luôn là một chủ đề gây tranh cãi, vì vậy chúng tôi cũng có thể giải quyết vấn đề
ngay. Các ns-3 dự án, giống như hầu hết các dự án lớn, đã áp dụng một phong cách mã hóa để
mà tất cả mã đóng góp phải tuân theo. Nếu bạn muốn đóng góp mã của mình vào
dự án, cuối cùng bạn sẽ phải tuân theo ns-3 tiêu chuẩn mã hóa như được mô tả trong
các tập tin doc / codingstd.txt hoặc hiển thị trên trang web của dự án vào đây.

Chúng tôi khuyên bạn nên làm quen với giao diện của ns-3 mã và áp dụng
tiêu chuẩn này bất cứ khi nào bạn đang làm việc với mã của chúng tôi. Tất cả nhóm phát triển và
những người đóng góp đã làm như vậy với rất nhiều lời càu nhàu. Dòng chế độ emacs ở trên
giúp bạn định dạng đúng hơn dễ dàng hơn nếu bạn sử dụng trình chỉnh sửa emacs.

Sản phẩm ns-3 trình mô phỏng được cấp phép sử dụng Giấy phép Công cộng GNU. Bạn sẽ thấy
GNU legalese thích hợp ở đầu mỗi tệp trong ns-3 phân bổ. Thường thì bạn
sẽ thấy thông báo bản quyền cho một trong những tổ chức liên quan đến ns-3 dự án trên
văn bản GPL và một tác giả được liệt kê bên dưới.

/*
* Chương trình này là phần mềm miễn phí; bạn có thể phân phối lại nó và / hoặc sửa đổi
* nó theo các điều khoản của Giấy phép Công cộng GNU phiên bản 2 như
* được xuất bản bởi Free Software Foundation;
*
* Chương trình này được phân phối với hy vọng rằng nó sẽ hữu ích,
* nhưng KHÔNG CÓ BẤT KỲ BẢO HÀNH NÀO; mà không có bảo hành ngụ ý
* KHẢ NĂNG LAO ĐỘNG hoặc PHÙ HỢP VỚI MỤC ĐÍCH CỤ THỂ. Xem
* Giấy phép Công cộng GNU để biết thêm chi tiết.
*
* Bạn đáng lẽ đã nhận được một bản sao của Giấy phép Công cộng GNU
* cùng với chương trình này; nếu không, hãy viết thư cho Phần mềm Miễn phí
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 Hoa Kỳ
*/

Mô-đun Bao gồm
Mã thích hợp bắt đầu với một số câu lệnh bao gồm.

#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3 / internet-module.h"
#include "ns3 / point-to-point-module.h"
#include "ns3 / apps-module.h"

Để giúp người dùng tập lệnh cấp cao của chúng tôi xử lý số lượng lớn các tệp bao gồm có trong
hệ thống, chúng tôi nhóm bao gồm theo các mô-đun tương đối lớn. Chúng tôi cung cấp một
bao gồm tệp sẽ tải một cách đệ quy tất cả các tệp bao gồm được sử dụng trong mỗi mô-đun.
Thay vì phải tra cứu chính xác tiêu đề bạn cần, và có thể phải lấy
đúng số lượng phụ thuộc, chúng tôi cung cấp cho bạn khả năng tải một nhóm tệp lớn
độ chi tiết. Đây không phải là cách tiếp cận hiệu quả nhất nhưng nó chắc chắn làm cho việc viết
tập lệnh dễ dàng hơn nhiều.

Mỗi ns-3 Bao gồm các tệp được đặt trong một thư mục có tên là Ns3 (đang xây dựng
thư mục) trong quá trình xây dựng để giúp tránh xung đột tên tệp bao gồm. Các
ns3 / core-module.h tệp tương ứng với mô-đun ns-3 mà bạn sẽ tìm thấy trong thư mục
src / core trong bản phân phối bản phát hành đã tải xuống của bạn. Nếu bạn liệt kê thư mục này, bạn sẽ
tìm một số lượng lớn các tệp tiêu đề. Khi bạn xây dựng, Waf sẽ đặt tiêu đề công khai
các tập tin trong một Ns3 thư mục dưới thích hợp xây dựng / gỡ lỗi or xây dựng / tối ưu hóa thư mục
tùy thuộc vào cấu hình của bạn. Waf cũng sẽ tự động tạo một mô-đun bao gồm
để tải tất cả các tệp tiêu đề công khai.

Tất nhiên, vì bạn đang làm theo hướng dẫn này về mặt tôn giáo, bạn sẽ làm được
a

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

để định cấu hình dự án để thực hiện các bản dựng gỡ lỗi bao gồm các ví dụ và thử nghiệm.
Bạn cũng sẽ làm một

$ ./waf

để xây dựng dự án. Vì vậy, bây giờ nếu bạn tìm trong danh bạ ../../build/debug/ns3 bạn sẽ
tìm bốn mô-đun bao gồm các tệp được hiển thị ở trên. Bạn có thể xem nội dung của
các tệp này và nhận thấy rằng chúng bao gồm tất cả các tệp bao gồm công khai trong
các mô-đun tương ứng.

Ns3 Không gian tên
Dòng tiếp theo trong đầu tiên.cc script là một khai báo không gian tên.

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

Sản phẩm ns-3 dự án được thực hiện trong không gian tên C ++ được gọi là Ns3. Nhóm này tất cả
ns-3-các khai báo liên quan trong một phạm vi bên ngoài không gian tên chung, chúng tôi hy vọng sẽ giúp
tích hợp với mã khác. C ++ sử dụng tuyên bố giới thiệu ns-3 không gian tên
vào khu vực khai báo (toàn cầu) hiện tại. Đây là một cách nói hoa mỹ để nói rằng sau khi
khai báo này, bạn sẽ không phải nhập ns3 :: toán tử phân giải phạm vi trước tất cả
các ns-3 mã để sử dụng nó. Nếu bạn không quen với không gian tên, vui lòng tham khảo
hầu hết mọi hướng dẫn C ++ và so sánh Ns3 không gian tên và cách sử dụng ở đây với các phiên bản của
tiêu chuẩn không gian tên và sử dụng không gian tên tiêu chuẩn; những câu nói bạn thường thấy trong các cuộc thảo luận
of cout và các luồng.

Logging
Dòng tiếp theo của script như sau,

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Chúng tôi sẽ sử dụng tuyên bố này như một nơi thuận tiện để nói về tài liệu Doxygen của chúng tôi
hệ thống. Nếu bạn nhìn vào trang web của dự án, ns-3 dự án, bạn sẽ tìm thấy một liên kết đến
"Tài liệu" trong thanh điều hướng. Nếu bạn chọn liên kết này, bạn sẽ được đưa đến
trang tài liệu. Có một liên kết đến "Bản phát hành mới nhất" sẽ đưa bạn đến
tài liệu cho bản phát hành ổn định mới nhất của ns-3. Nếu bạn chọn "API
Liên kết tài liệu ", bạn sẽ được đưa đến ns-3 Trang tài liệu API.

Dọc theo phía bên trái, bạn sẽ tìm thấy một biểu diễn đồ họa về cấu trúc của
tài liệu. Một nơi tốt để bắt đầu là NS-3 Modules "cuốn sách" trong ns-3 chuyển hướng
cây. Nếu bạn mở rộng Modules bạn sẽ thấy một danh sách ns-3 tài liệu mô-đun. Các
khái niệm mô-đun ở đây liên kết trực tiếp với mô-đun bao gồm các tệp đã thảo luận ở trên. Các
ns-3 hệ thống con ghi nhật ký được thảo luận trong C + + Cấu tạo Đã sử dụng by Tất cả Modules phần, vì vậy
hãy tiếp tục và mở rộng nút tài liệu đó. Bây giờ, hãy mở rộng Gỡ lỗi cuốn sách và sau đó
chọn Logging .

Bây giờ bạn sẽ xem tài liệu Doxygen cho mô-đun Ghi nhật ký. bên trong
danh sách của #định nghĩaở đầu trang, bạn sẽ thấy mục nhập
NS_LOG_COMPONENT_DEFINE. Trước khi nhảy vào, có lẽ sẽ tốt hơn nếu bạn tìm kiếm
"Mô tả chi tiết" của mô-đun ghi nhật ký để có cảm nhận về hoạt động tổng thể. Bạn
có thể cuộn xuống hoặc chọn liên kết "Thêm ..." trong sơ đồ cộng tác để thực hiện
cái này.

Khi bạn có ý tưởng chung về những gì đang diễn ra, hãy tiếp tục và xem xét cụ thể
NS_LOG_COMPONENT_DEFINE tài liệu. Tôi sẽ không sao chép tài liệu ở đây, nhưng để
tóm tắt, dòng này khai báo một thành phần ghi nhật ký được gọi là FirstScriptVí dụ điều đó cho phép
bạn có thể bật và tắt ghi nhật ký thông báo trên bảng điều khiển bằng cách tham chiếu đến tên.

Chủ yếu Chức năng
Các dòng tiếp theo của tập lệnh mà bạn sẽ tìm thấy là,

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

Đây chỉ là phần khai báo chức năng chính của chương trình (script) của bạn. Cũng như trong
bất kỳ chương trình C ++ nào, bạn cần xác định một hàm chính sẽ là hàm chạy đầu tiên.
Không có gì đặc biệt ở đây. Của bạn ns-3 script chỉ là một chương trình C ++.

Dòng tiếp theo đặt độ phân giải thời gian thành một nano giây, đây là giá trị mặc định
giá trị:

Thời gian :: SetResolution (Thời gian :: NS);

Độ phân giải là giá trị thời gian nhỏ nhất có thể được biểu diễn (cũng như nhỏ nhất
sự khác biệt có thể biểu diễn giữa hai giá trị thời gian). Bạn có thể thay đổi độ phân giải chính xác
Một lần. Cơ chế cho phép tính linh hoạt này hơi đói bộ nhớ, vì vậy một khi
độ phân giải đã được thiết lập rõ ràng, chúng tôi giải phóng bộ nhớ, ngăn cập nhật thêm.
(Nếu bạn không đặt độ phân giải một cách rõ ràng, nó sẽ mặc định là một nano giây và
bộ nhớ sẽ được giải phóng khi bắt đầu mô phỏng.)

Hai dòng tiếp theo của tập lệnh được sử dụng để kích hoạt hai thành phần ghi nhật ký được xây dựng
vào các ứng dụng Echo Client và Echo Server:

LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);

Nếu bạn đã đọc qua tài liệu về thành phần Ghi nhật ký, bạn sẽ thấy rằng ở đó
là một số cấp độ chi tiết / chi tiết của việc ghi nhật ký mà bạn có thể bật trên mỗi thành phần.
Hai dòng mã này cho phép ghi nhật ký gỡ lỗi ở cấp INFO cho các ứng dụng khách echo và
may chủ. Điều này sẽ dẫn đến việc ứng dụng in ra các thông báo khi các gói được gửi đi
và nhận được trong quá trình mô phỏng.

Bây giờ chúng ta sẽ trực tiếp đến công việc tạo cấu trúc liên kết và chạy mô phỏng.
Chúng tôi sử dụng các đối tượng trình trợ giúp cấu trúc liên kết để thực hiện công việc này dễ dàng nhất có thể.

topology Người giúp việc
NútContainer
Hai dòng mã tiếp theo trong tập lệnh của chúng tôi sẽ thực sự tạo ra ns-3 Node đối tượng mà
sẽ đại diện cho các máy tính trong mô phỏng.

Các nút NodeContainer;
các nút.Create (2);

Hãy cùng tìm tài liệu cho NútContainer lớp học trước khi chúng ta tiếp tục. Cách khác
để truy cập vào tài liệu cho một lớp nhất định là thông qua Các lớp học tab trong Doxygen
các trang. Nếu bạn vẫn có Doxygen, chỉ cần cuộn lên đầu trang và
chọn Các lớp học chuyển hướng. Bạn sẽ thấy một tập hợp các tab mới xuất hiện, một trong số đó là Lớp
Danh sách. Trong tab đó, bạn sẽ thấy danh sách tất cả các ns-3 các lớp học. Cuộn xuống,
tìm kiếm ns3 :: NodeContainer. Khi bạn tìm thấy lớp học, hãy tiếp tục và chọn lớp học đó để chuyển đến
tài liệu cho lớp học.

Bạn có thể nhớ rằng một trong những điểm tóm tắt chính của chúng tôi là Node. Điều này đại diện cho một máy tính
mà chúng tôi sẽ thêm những thứ như ngăn xếp giao thức, ứng dụng và thiết bị ngoại vi
thẻ. Các NútContainer trình trợ giúp cấu trúc liên kết cung cấp một cách thuận tiện để tạo, quản lý và
truy cập bất kỳ Node các đối tượng mà chúng tôi tạo để chạy mô phỏng. Dòng đầu tiên ở trên
chỉ cần khai báo một NodeContainer mà chúng tôi gọi các nút. Dòng thứ hai gọi Tạo
phương pháp trên các nút đối tượng và yêu cầu vùng chứa tạo hai nút. Như được mô tả trong
Doxygen, vùng chứa gọi xuống ns-3 hệ thống thích hợp để tạo ra hai Node
các đối tượng và lưu trữ các con trỏ tới các đối tượng đó trong nội bộ.

Các nút khi chúng đứng trong tập lệnh không làm gì cả. Bước tiếp theo trong việc xây dựng một
cấu trúc liên kết là kết nối các nút của chúng ta với nhau thành một mạng. Hình thức đơn giản nhất của mạng chúng tôi
hỗ trợ là một liên kết điểm-điểm giữa hai nút. Chúng tôi sẽ xây dựng một trong những
liên kết ở đây.

PointToPointTrợ giúp
Chúng tôi đang xây dựng một liên kết điểm tới điểm và theo một mô hình sẽ trở nên khá
quen thuộc với bạn, chúng tôi sử dụng đối tượng trình trợ giúp cấu trúc liên kết để thực hiện công việc cấp thấp cần thiết để đưa
liên kết với nhau. Hãy nhớ lại rằng hai trong số những điều trừu tượng chính của chúng ta là thiết bị mạng
Kênh. Trong thế giới thực, những thuật ngữ này gần tương ứng với thẻ ngoại vi và
cáp mạng. Điển hình là hai thứ này gắn bó mật thiết với nhau và một thứ không thể
mong đợi để trao đổi, ví dụ, thiết bị Ethernet và các kênh không dây. Cấu trúc liên kết của chúng tôi
Những người trợ giúp tuân theo sự kết hợp mật thiết này và do đó bạn sẽ sử dụng một
PointToPointTrợ giúp để cấu hình và kết nối ns-3 PointToPointNetThiết bị
Điểm Đến ĐiểmKênh các đối tượng trong tập lệnh này.

Ba dòng tiếp theo trong kịch bản là,

PointToPointTrợ giúp pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

Dòng đầu tiên,

PointToPointTrợ giúp pointToPoint;

tạo ra một PointToPointTrợ giúp đối tượng trên ngăn xếp. Từ quan điểm cấp cao,
hàng tiếp theo,

pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));

nói với PointToPointTrợ giúp đối tượng sử dụng giá trị "5Mbps" (năm megabit mỗi giây) làm
"DataRate" khi nó tạo PointToPointNetThiết bị vật.

Từ một góc độ chi tiết hơn, chuỗi "DataRate" tương ứng với cái mà chúng tôi gọi là
đặc tính của PointToPointNetThiết bị. Nếu bạn nhìn vào Doxygen cho lớp
ns3 :: PointToPointNetDevice và tìm tài liệu cho GetTypeId phương pháp, bạn sẽ
tìm một danh sách Thuộc tính được xác định cho thiết bị. Trong số này có "DataRate"
đặc tính. Người dùng dễ thấy nhất ns-3 các đối tượng có danh sách tương tự về Thuộc tính. Chúng tôi sử dụng cái này
cơ chế để dễ dàng định cấu hình mô phỏng mà không cần biên dịch lại như bạn sẽ thấy trong
Phần sau.

Tương tự như "DataRate" trên PointToPointNetThiết bị bạn sẽ thấy một "Trì hoãn" đặc tính
Liên quan đến Điểm Đến ĐiểmKênh. Dòng cuối cùng,

pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

nói với PointToPointTrợ giúp để sử dụng giá trị "2ms" (hai mili giây) làm giá trị của
độ trễ truyền của mọi kênh điểm đến điểm mà nó tạo ra sau đó.

NetThiết BịContainer
Tại thời điểm này trong tập lệnh, chúng ta có NútContainer chứa hai nút. Chúng ta có một
PointToPointTrợ giúp nó đã được sơn lót và sẵn sàng để làm PointToPointNetThiết bị và dây
Điểm Đến ĐiểmKênh các đối tượng giữa chúng. Cũng giống như chúng tôi đã sử dụng NútContainer cấu trúc liên kết
đối tượng trợ giúp để tạo Nodes đối với mô phỏng của chúng tôi, chúng tôi sẽ hỏi PointToPointTrợ giúp
để thực hiện công việc liên quan đến việc tạo, cấu hình và cài đặt các thiết bị của chúng tôi cho chúng tôi. chúng tôi
sẽ cần có danh sách tất cả các đối tượng NetDevice được tạo, vì vậy chúng tôi sử dụng
NetDeviceContainer để giữ chúng giống như chúng ta sử dụng NodeContainer để giữ các nút mà chúng ta
tạo. Hai dòng mã sau,

Thiết bị NetDeviceContainer;
thiết bị = pointToPoint.Install (các nút);

sẽ hoàn tất việc định cấu hình các thiết bị và kênh. Dòng đầu tiên khai báo thiết bị
container được đề cập ở trên và thứ hai là nâng vật nặng. Các đặt phương pháp
các PointToPointTrợ giúp mất một NútContainer như một tham số. Trong nội bộ, một
NetThiết BịContainer được tạo ra. Đối với mỗi nút trong NútContainer (phải có chính xác
hai cho liên kết điểm-điểm) a PointToPointNetThiết bị được tạo và lưu trong thiết bị
thùng đựng hàng. MỘT Điểm Đến ĐiểmKênh được tạo ra và hai PointToPointNetThiết bị đang
đính kèm. Khi các đối tượng được tạo bởi PointToPointTrợ giúp, Các Thuộc tính trước đây
thiết lập trong trình trợ giúp được sử dụng để khởi tạo Thuộc tính trong tạo ra
các đối tượng.

Sau khi thực hiện pointToPoint.Cài đặt (điểm giao) gọi, chúng tôi sẽ có hai nút, mỗi nút có một
đã cài đặt thiết bị mạng điểm-điểm và một kênh điểm-điểm duy nhất giữa chúng.
Cả hai thiết bị sẽ được định cấu hình để truyền dữ liệu với tốc độ XNUMX megabit / giây qua
kênh có độ trễ truyền hai phần nghìn giây.

InternetNgăn XếpTrợ Giúp
Bây giờ chúng tôi đã định cấu hình các nút và thiết bị, nhưng chúng tôi chưa cài đặt bất kỳ ngăn xếp giao thức nào
trên các nút của chúng tôi. Hai dòng mã tiếp theo sẽ giải quyết vấn đề đó.

Ngăn xếp InternetStackHelper;
stack.Install (các nút);

Sản phẩm InternetNgăn XếpTrợ Giúp là một trình trợ giúp cấu trúc liên kết dùng để ngăn xếp internet những gì
PointToPointTrợ giúp là thiết bị mạng điểm-điểm. Các đặt phương pháp mất một
NútContainer như một tham số. Khi nó được thực thi, nó sẽ cài đặt một Internet Stack
(TCP, UDP, IP, v.v.) trên mỗi nút trong vùng chứa nút.

Trình trợ giúp địa chỉ Ipv4
Tiếp theo, chúng ta cần liên kết các thiết bị trên các nút với địa chỉ IP. Chúng tôi cung cấp một
trình trợ giúp cấu trúc liên kết để quản lý việc cấp phát địa chỉ IP. API duy nhất mà người dùng có thể nhìn thấy là
đặt địa chỉ IP cơ sở và mặt nạ mạng để sử dụng khi thực hiện địa chỉ thực
phân bổ (được thực hiện ở cấp thấp hơn bên trong trình trợ giúp).

Hai dòng mã tiếp theo trong tập lệnh mẫu của chúng tôi, đầu tiên.cc,

Địa chỉ Ipv4AddressHelper;
address.SetBase ("10.1.1.0", "255.255.255.0");

khai báo một đối tượng trình trợ giúp địa chỉ và nói với nó rằng nó sẽ bắt đầu cấp phát địa chỉ IP
từ mạng 10.1.1.0 sử dụng mặt nạ 255.255.255.0 để xác định các bit có thể phân bổ. Qua
mặc định, các địa chỉ được cấp phát sẽ bắt đầu từ một và tăng đơn điệu, vì vậy địa chỉ đầu tiên
địa chỉ được phân bổ từ cơ sở này sẽ là 10.1.1.1, tiếp theo là 10.1.1.2, v.v. Mức thấp
cấp ns-3 hệ thống thực sự ghi nhớ tất cả các địa chỉ IP được cấp phát và sẽ tạo ra một
lỗi nghiêm trọng nếu bạn vô tình làm cho cùng một địa chỉ được tạo hai lần (đó là
nhân tiện, rất khó để gỡ lỗi).

Dòng mã tiếp theo,

Ipv4InterfaceContainer interface = address.Assign (thiết bị);

thực hiện việc gán địa chỉ thực tế. Trong ns-3 chúng tôi tạo sự liên kết giữa một IP
địa chỉ và một thiết bị sử dụng Giao diện Ipv4 sự vật. Cũng như đôi khi chúng ta cần một danh sách
thiết bị net được tạo bởi một người trợ giúp để tham khảo trong tương lai, chúng tôi đôi khi cần một danh sách
Giao diện Ipv4 các đối tượng. Các Bộ chứa giao diện Ipv4 cung cấp chức năng này.

Bây giờ chúng tôi đã xây dựng một mạng điểm-điểm, với các ngăn xếp được cài đặt và địa chỉ IP
giao. Những gì chúng ta cần ở thời điểm này là các ứng dụng để tạo ra lưu lượng truy cập.

Ứng dụng
Một trong những điểm trừu tượng cốt lõi khác của hệ thống ns-3 là Các Ứng Dụng. Trong
tập lệnh chúng tôi sử dụng hai chuyên môn của cốt lõi ns-3 tốt nghiệp lớp XNUMX Các Ứng Dụng gọi là
Ứng dụng UdpEchoServerỨng dụng UdpEchoClient. Cũng giống như chúng tôi đã có trong phần trước của chúng tôi
giải thích, chúng tôi sử dụng các đối tượng trợ giúp để giúp định cấu hình và quản lý các đối tượng bên dưới.
Ở đây, chúng tôi sử dụng UdpEchoMáy ChủTrợ GiúpUdpEchoClientTrợ giúp để làm cho cuộc sống của chúng ta dễ dàng hơn.

UdpEchoMáy ChủTrợ Giúp
Các dòng mã sau trong tập lệnh mẫu của chúng tôi, đầu tiên.cc, được sử dụng để thiết lập tiếng vọng UDP
ứng dụng máy chủ trên một trong các nút mà chúng tôi đã tạo trước đó.

UdpEchoServerTrợ giúp echoServer (9);

ApplicationContainer serverApps = echoServer.Install (node.Get (1));
serverApps.Start (Giây (1.0));
serverApps.Stop (Giây (10.0));

Dòng mã đầu tiên trong đoạn mã trên khai báo UdpEchoMáy ChủTrợ Giúp. Như thường lệ,
đây không phải là bản thân ứng dụng, nó là một đối tượng được sử dụng để giúp chúng tôi tạo
các ứng dụng. Một trong những quy ước của chúng tôi là đặt cần phải Thuộc tính trong người trợ giúp
constructor. Trong trường hợp này, người trợ giúp không thể làm bất cứ điều gì hữu ích trừ khi nó được cung cấp
số cổng mà khách hàng cũng biết. Thay vì chỉ chọn một và hy vọng
tất cả đều hoạt động, chúng tôi yêu cầu số cổng làm tham số cho hàm tạo. Các
đến lượt nó, hàm tạo chỉ đơn giản thực hiện một Đặt thuộc tính với giá trị được truyền. Nếu bạn muốn bạn
có thể đặt "Cổng" đặc tính sang giá trị khác sau này bằng cách sử dụng Đặt thuộc tính.

Tương tự như nhiều đối tượng trợ giúp khác, UdpEchoMáy ChủTrợ Giúp đối tượng có một đặt
phương pháp. Chính việc thực thi phương pháp này thực sự gây ra tiếng vang cơ bản
ứng dụng máy chủ sẽ được khởi tạo và gắn vào một nút. Thật thú vị, đặt
phương pháp mất một NútContainter như một tham số giống như tham số khác đặt phương pháp chúng tôi có
đã xem. Đây thực sự là những gì được truyền cho phương thức mặc dù nó trông không giống như vậy
trường hợp này. Có một C ++ ngầm Chuyển đổi tại nơi làm việc ở đây có kết quả là
node.Get (1) (trả về một con trỏ thông minh cho một đối tượng nút --- Ptr) và sử dụng
trong một phương thức khởi tạo cho một NútContainer điều đó sau đó được chuyển cho đặt. Nếu bạn là
không bao giờ gặp khó khăn khi tìm một chữ ký phương thức cụ thể trong mã C ++ để biên dịch và chạy
tốt thôi, hãy tìm những loại chuyển đổi ngầm này.

Bây giờ chúng ta thấy rằng echoServer.Cài đặt sẽ cài đặt một Ứng dụng UdpEchoServer trên
nút được tìm thấy ở chỉ mục số một trong số NútContainer chúng tôi đã từng quản lý các nút của mình. đặt
sẽ trả về một vùng chứa chứa các con trỏ đến tất cả các ứng dụng (trong trường hợp này là một
kể từ khi chúng tôi vượt qua một NútContainer chứa một nút) được tạo bởi trình trợ giúp.

Các ứng dụng yêu cầu một thời gian để "bắt đầu" tạo ra lưu lượng truy cập và có thể mất một thời gian tùy chọn để
"dừng lại". Chúng tôi cung cấp cả hai. Những thời gian này được đặt bằng cách sử dụng Ứng DụngContainer phương pháp
Bắt đầuDừng. Những phương pháp này có Thời gian thông số. Trong trường hợp này, chúng tôi sử dụng một rõ ràng C + +
chuỗi chuyển đổi để lấy C ++ double 1.0 và chuyển đổi nó thành một ns-3 Thời gian đối tượng sử dụng
a Giây dàn diễn viên. Lưu ý rằng các quy tắc chuyển đổi có thể được kiểm soát bởi tác giả mô hình,
và C ++ có các quy tắc riêng của nó, vì vậy bạn không phải lúc nào cũng giả định rằng các tham số sẽ hạnh phúc
đã chuyển đổi cho bạn. Hai dòng,

serverApps.Start (Giây (1.0));
serverApps.Stop (Giây (10.0));

sẽ khiến ứng dụng máy chủ echo Bắt đầu (tự kích hoạt) trong một giây vào
mô phỏng và để Dừng (vô hiệu hóa chính nó) sau mười giây sau khi mô phỏng. Bởi Đức hạnh của
thực tế là chúng tôi đã khai báo một sự kiện mô phỏng (sự kiện dừng ứng dụng) là
được thực hiện ở XNUMX giây, mô phỏng sẽ kéo dài at ít nhất mười giây.

UdpEchoClientTrợ giúp
Ứng dụng máy khách echo được thiết lập theo một phương pháp về cơ bản tương tự như cho
máy chủ. Có một cơ bản Ứng dụng UdpEchoClient được quản lý bởi một
UdpEchoClientTrợ giúp.

UdpEchoClientHelper echoClient (giao diện.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Khoảng thời gian", TimeValue (Giây (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (node.Get (0));
clientApps.Start (Giây (2.0));
clientApps.Stop (Giây (10.0));

Tuy nhiên, đối với ứng dụng khách echo, chúng ta cần đặt năm Thuộc tính. Hai đầu tiên
Thuộc tính được thiết lập trong quá trình xây dựng UdpEchoClientTrợ giúp. Chúng tôi chuyển các tham số
được sử dụng (nội bộ cho người trợ giúp) để đặt "Địa chỉ từ xa" và "Địa chỉ từ xa"
Thuộc tính phù hợp với quy ước của chúng tôi để thực hiện yêu cầu Thuộc tính tham số trong
các hàm tạo trợ giúp.

Nhớ lại rằng chúng tôi đã sử dụng một Bộ chứa giao diện Ipv4 để theo dõi các địa chỉ IP, chúng tôi
được chỉ định cho các thiết bị của chúng tôi. Giao diện thứ XNUMX trong giao diện container sẽ
tương ứng với địa chỉ IP của nút thứ XNUMX trong các nút thùng đựng hàng. Người đầu tiên
giao diện trong giao diện vùng chứa tương ứng với địa chỉ IP của nút đầu tiên trong
các các nút thùng đựng hàng. Vì vậy, trong dòng mã đầu tiên (từ phía trên), chúng tôi đang tạo
người trợ giúp và nói với nó để đặt địa chỉ từ xa của máy khách là địa chỉ IP
được gán cho nút mà máy chủ cư trú. Chúng tôi cũng nói với nó để sắp xếp để gửi
gói đến cổng chín.

"MaxPackets" đặc tính cho khách hàng biết số lượng gói tối đa mà chúng tôi cho phép
gửi trong quá trình mô phỏng. Khoảng thời gian" đặc tính cho khách hàng biết phải đợi bao lâu
giữa các gói và "PacketSize" đặc tính cho khách hàng biết gói của nó lớn như thế nào
trọng tải nên được. Với sự kết hợp đặc biệt này của Thuộc tính, chúng tôi đang nói với
khách hàng để gửi một gói 1024 byte.

Cũng giống như trong trường hợp máy chủ echo, chúng tôi yêu cầu máy khách echo Bắt đầuDừng, Nhưng
ở đây, chúng tôi bắt đầu ứng dụng khách một giây sau khi máy chủ được kích hoạt (sau hai giây sau
mô phỏng).

Simulator
Những gì chúng ta cần làm lúc này là thực sự chạy mô phỏng. Điều này được thực hiện bằng cách sử dụng
chức năng toàn cầu Trình mô phỏng :: Chạy.

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

Khi trước đây chúng tôi gọi các phương thức,

serverApps.Start (Giây (1.0));
serverApps.Stop (Giây (10.0));
...
clientApps.Start (Giây (2.0));
clientApps.Stop (Giây (10.0));

chúng tôi thực sự đã lên lịch các sự kiện trong trình mô phỏng ở 1.0 giây, 2.0 giây và hai sự kiện
ở 10.0 giây. Khi nào Trình mô phỏng :: Chạy được gọi, hệ thống sẽ bắt đầu xem xét
danh sách các sự kiện đã lên lịch và thực hiện chúng. Đầu tiên, nó sẽ chạy sự kiện với tốc độ 1.0 giây,
điều này sẽ kích hoạt ứng dụng máy chủ tiếng vang (sự kiện này, đến lượt nó, có thể lên lịch cho nhiều
Các sự kiện khác). Sau đó, nó sẽ chạy sự kiện được lên lịch trong t = 2.0 giây sẽ bắt đầu
ứng dụng máy khách echo. Một lần nữa, sự kiện này có thể lên lịch cho nhiều sự kiện khác. Bắt đầu
triển khai sự kiện trong ứng dụng máy khách echo sẽ bắt đầu giai đoạn truyền dữ liệu của
mô phỏng bằng cách gửi một gói đến máy chủ.

Hành động gửi gói đến máy chủ sẽ kích hoạt một chuỗi các sự kiện sẽ
được lên lịch tự động ở hậu trường và sẽ thực hiện cơ chế của
gói echo theo các tham số thời gian khác nhau mà chúng ta đã thiết lập trong script.

Cuối cùng, vì chúng tôi chỉ gửi một gói (nhớ lại Gói tối đa đặc tính đã được đặt thành
một), chuỗi sự kiện được kích hoạt bởi yêu cầu phản hồi của khách hàng duy nhất đó sẽ giảm dần và
mô phỏng sẽ không hoạt động. Khi điều này xảy ra, các sự kiện còn lại sẽ là Dừng
sự kiện cho máy chủ và máy khách. Khi các sự kiện này được thực thi, không có
các sự kiện khác để xử lý và Trình mô phỏng :: Chạy lợi nhuận. Mô phỏng sau đó hoàn tất.

Tất cả những gì còn lại là để dọn dẹp. Điều này được thực hiện bằng cách gọi hàm toàn cầu
Trình mô phỏng :: Phá hủy. Khi người trợ giúp hoạt động (hoặc cấp thấp ns-3 mã) được thực thi, họ
sắp xếp nó sao cho các móc được lắp vào trình mô phỏng để phá hủy tất cả các đối tượng
đã được tạo. Bạn không cần phải tự mình theo dõi bất kỳ đối tượng nào trong số này ---
tất cả những gì bạn phải làm là gọi Trình mô phỏng :: Phá hủy và thoát ra. Các ns-3 hệ thống đã chăm sóc
phần khó cho bạn. Các dòng còn lại của đầu tiên của chúng tôi ns-3 kịch bản, đầu tiên.cc, chỉ làm
rằng:

Trình mô phỏng :: Phá hủy ();
0 trở về;
}

Thời Gian các mô phỏng sẽ dừng lại?
ns-3 là một trình mô phỏng Sự kiện Rời rạc (DE). Trong một trình mô phỏng như vậy, mỗi sự kiện được liên kết
với thời gian thực hiện của nó và quá trình mô phỏng tiến hành bằng cách thực hiện các sự kiện trong thời gian
thứ tự của thời gian mô phỏng. Các sự kiện có thể khiến các sự kiện trong tương lai được lên lịch (ví dụ:
bộ đếm thời gian có thể tự lên lịch để hết hạn vào khoảng thời gian tiếp theo).

Các sự kiện ban đầu thường được kích hoạt bởi từng đối tượng, ví dụ: IPv6 sẽ lên lịch cho Bộ định tuyến
Quảng cáo, Gạ gẫm hàng xóm, v.v., một Ứng dụng lên lịch cho gói đầu tiên
gửi sự kiện, v.v.

Khi một sự kiện được xử lý, nó có thể tạo ra không, một hoặc nhiều sự kiện. Như một mô phỏng
thực thi, các sự kiện được sử dụng, nhưng nhiều sự kiện hơn có thể (hoặc có thể không) được tạo ra. Các
mô phỏng sẽ tự động dừng khi không có sự kiện nào khác trong hàng đợi sự kiện hoặc khi
một sự kiện dừng đặc biệt được tìm thấy. Sự kiện Dừng được tạo thông qua Trình mô phỏng :: Dừng lại
(thời gian dừng); chức năng.

Có một trường hợp điển hình là Trình mô phỏng :: Dừng lại là hoàn toàn cần thiết để ngăn chặn
mô phỏng: khi có sự kiện tự duy trì. Sự kiện tự duy trì (hoặc lặp lại)
là những sự kiện luôn tự lên lịch lại. Do đó, họ luôn duy trì sự kiện
hàng đợi không trống.

Có nhiều giao thức và mô-đun chứa các sự kiện lặp lại, ví dụ:

· FlowMonitor - kiểm tra định kỳ các gói bị mất

· RIPng - cập nhật bảng định tuyến phát sóng định kỳ

· Vân vân.

Trong những trường hợp này, Trình mô phỏng :: Dừng lại là cần thiết để dừng mô phỏng một cách duyên dáng. Trong
ngoài ra, khi ns-3 đang ở chế độ giả lập, Thời gian thựcTrình mô phỏng được sử dụng để giữ
đồng hồ mô phỏng được căn chỉnh với đồng hồ máy và Trình mô phỏng :: Dừng lại là cần thiết để dừng lại
quá trình.

Nhiều chương trình mô phỏng trong hướng dẫn này không gọi một cách rõ ràng Trình mô phỏng :: Dừng lại,
vì hàng đợi sự kiện sẽ tự động hết sự kiện. Tuy nhiên, các chương trình này sẽ
cũng chấp nhận một cuộc gọi đến Trình mô phỏng :: Dừng lại. Ví dụ: câu lệnh bổ sung sau trong
chương trình ví dụ đầu tiên sẽ lên lịch dừng rõ ràng ở 11 giây:

+ Trình mô phỏng :: Dừng (Giây (11.0));
Trình mô phỏng :: Run ();
Trình mô phỏng :: Phá hủy ();
0 trở về;
}

Phần trên sẽ không thực sự thay đổi hành vi của chương trình này, vì
mô phỏng tự nhiên kết thúc sau 10 giây. Nhưng nếu bạn thay đổi thời gian dừng trong
câu lệnh trên từ 11 giây đến 1 giây, bạn sẽ nhận thấy rằng mô phỏng
dừng trước khi bất kỳ đầu ra nào được in ra màn hình (vì đầu ra xảy ra vào khoảng thời gian 2
giây của thời gian mô phỏng).

Điều quan trọng là phải gọi Trình mô phỏng :: Dừng lại trước gọi Trình mô phỏng :: Chạy; nếu không thì,
Trình mô phỏng :: Chạy có thể không bao giờ trả lại quyền điều khiển cho chương trình chính để thực hiện lệnh dừng!

Xây dựng trên màn hình Script
Chúng tôi đã làm cho việc xây dựng các tập lệnh đơn giản của bạn trở nên tầm thường. Tất cả những gì bạn phải làm là bỏ
script vào thư mục xước và nó sẽ tự động được tạo nếu bạn chạy Waf.
Hãy thử nó. Sao chép ví dụ / hướng dẫn / first.cc vào xước thư mục sau khi thay đổi
trở lại thư mục cấp cao nhất.

$cd../ ..
Các ví dụ về $ cp / hướng dẫn / first.cc xước / myfirst.cc

Bây giờ, hãy xây dựng tập lệnh mẫu đầu tiên của bạn bằng cách sử dụng waf:

$ ./waf

Bạn sẽ thấy các thông báo báo cáo rằng lần đầu tiên của tôi ví dụ đã được xây dựng thành công.

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
[614/708] cxx: xước / myfirst.cc -> xây dựng / gỡ lỗi / cào / myfirst_3.o
[706/708] cxx_link: build / debug / xước / myfirst_3.o -> build / debug / xước / myfirst
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (2.357 giây)

Bây giờ bạn có thể chạy ví dụ (lưu ý rằng nếu bạn xây dựng chương trình của mình trong thư mục đầu
bạn phải chạy nó ra khỏi thư mục đầu):

$ ./waf --run cào / myfirst

Bạn sẽ thấy một số đầu ra:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.418 giây)
Đã gửi 1024 byte tới 10.1.1.2
Đã nhận 1024 byte từ 10.1.1.1
Đã nhận 1024 byte từ 10.1.1.2

Ở đây, bạn thấy rằng hệ thống xây dựng sẽ kiểm tra để đảm bảo rằng tệp đã được xây dựng và
sau đó chạy nó. Bạn thấy thành phần ghi nhật ký trên máy khách echo cho biết rằng nó đã gửi
một gói 1024 byte tới Máy chủ Echo trên 10.1.1.2. Bạn cũng thấy thành phần ghi nhật ký
trên máy chủ echo nói rằng nó đã nhận được 1024 byte từ 10.1.1.1. Máy chủ echo
âm thầm lặp lại gói tin và bạn thấy nhật ký ứng dụng khách echo rằng nó đã nhận được gói tin của nó
trở lại từ máy chủ.

Ns-3 nguồn
Bây giờ bạn đã sử dụng một số ns-3 những người trợ giúp bạn có thể muốn xem một số
mã nguồn thực hiện chức năng đó. Mã gần đây nhất có thể được duyệt trên
máy chủ web của chúng tôi tại liên kết sau: http://code.nsnam.org/ns-3-dev. Ở đó, bạn sẽ thấy
trang tóm tắt Mercurial cho ns-3 cây phát triển.

Ở đầu trang, bạn sẽ thấy một số liên kết,

tóm tắt | shortlog | changelog | đồ thị | thẻ | các tập tin

Hãy tiếp tục và chọn các tập tin liên kết. Đây là cấp cao nhất của hầu hết
kho sẽ nhìn:

drwxr-xr-x [lên]
drwxr-xr-x ràng buộc tệp python
tệp doc drwxr-xr-x
tệp ví dụ drwxr-xr-x
tệp drwxr-xr-x ns3
tệp tin xước drwxr-xr-x
tệp drwxr-xr-x src
tệp drwxr-xr-x utils
-rw-r - r-- 2009-07-01 12:47 +0200 560 .hgignore tệp | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 1886 .hgtags tệp | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 1276 TÁC GIẢ | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 30961 CHANGES.html tệp | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 17987 Tệp GIẤY PHÉP | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 3742 Tệp README | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 16171 Tệp RELEASE_NOTES | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 6 Tệp PHIÊN BẢN | sửa đổi | chú thích
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 tệp waf | sửa đổi | chú thích
-rwxr-xr-x 2009-07-01 12:47 +0200 28 tệp waf.bat | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 35395 tệp wscript | sửa đổi | chú thích
-rw-r - r-- 2009-07-01 12:47 +0200 7673 tệp wutils.py | sửa đổi | chú thích

Các tập lệnh mẫu của chúng tôi nằm trong ví dụ danh mục. Nếu bạn nhấp vào ví dụ Bạn sẽ thấy
một danh sách các thư mục con. Một trong những tệp trong hướng dẫn thư mục con là đầu tiên.cc. Nếu bạn
bấm vào đầu tiên.cc bạn sẽ tìm thấy mã bạn vừa xem qua.

Mã nguồn chủ yếu nằm trong src danh mục. Bạn có thể xem mã nguồn bằng cách
nhấp vào tên thư mục hoặc bằng cách nhấp vào các tập tin liên kết ở bên phải của
Tên thư mục. Nếu bạn nhấp vào src thư mục, bạn sẽ được đưa đến danh sách của
các src các thư mục con. Nếu sau đó bạn nhấp vào cốt lõi thư mục con, bạn sẽ tìm thấy một danh sách
các tập tin. Tệp đầu tiên bạn sẽ tìm thấy (khi viết bài này) là hủy bỏ.h. Nếu bạn nhấp vào
hủy bỏ.h liên kết, bạn sẽ được chuyển đến tệp nguồn cho hủy bỏ.h trong đó chứa các macro hữu ích
để thoát các tập lệnh nếu phát hiện các điều kiện bất thường.

Bạn có thể tìm thấy mã nguồn cho các trình trợ giúp mà chúng tôi đã sử dụng trong chương này trong
src / Applications / helper danh mục. Vui lòng xem qua cây thư mục để lấy
cảm nhận về những gì ở đó và phong cách của ns-3 chương trình.

CHỈNH SỬA


Sử dụng các Logging Mô-đun
Chúng tôi đã có một cái nhìn ngắn gọn về ns-3 mô-đun ghi nhật ký trong khi xem qua
đầu tiên.cc script. Bây giờ chúng ta sẽ xem xét kỹ hơn và xem loại trường hợp sử dụng nào
hệ thống con ghi nhật ký được thiết kế để bao gồm.

Logging Giới thiệu chung
Nhiều hệ thống lớn hỗ trợ một số loại phương tiện ghi tin nhắn, và ns-3 không phải là một
ngoại lệ. Trong một số trường hợp, chỉ các thông báo lỗi mới được ghi vào "bảng điều khiển" (bảng điều khiển
thường là tiêu chuẩn trong hệ thống dựa trên Unix). Trong các hệ thống khác, các thông báo cảnh báo có thể
đầu ra cũng như các thông điệp thông tin chi tiết hơn. Trong một số trường hợp, các phương tiện khai thác
được sử dụng để xuất ra các thông báo gỡ lỗi có thể nhanh chóng biến đầu ra thành một màn hình mờ.

ns-3 có quan điểm rằng tất cả các mức độ chi tiết này đều hữu ích và chúng tôi cung cấp
có thể lựa chọn, cách tiếp cận đa cấp để ghi nhật ký tin nhắn. Ghi nhật ký có thể bị vô hiệu hóa hoàn toàn,
được kích hoạt trên cơ sở từng thành phần hoặc được kích hoạt trên toàn cầu; và nó cung cấp
mức độ chi tiết. Các ns-3 mô-đun nhật ký cung cấp một mô-đun đơn giản, tương đối dễ sử dụng
cách để nhận thông tin hữu ích từ mô phỏng của bạn.

Bạn nên hiểu rằng chúng tôi cung cấp một cơ chế mục đích chung --- truy tìm --- để
lấy dữ liệu ra khỏi các mô hình của bạn, mô hình này sẽ được ưu tiên cho đầu ra mô phỏng (xem
phần hướng dẫn Sử dụng Hệ thống truy tìm để biết thêm chi tiết về hệ thống truy tìm của chúng tôi).
Ghi nhật ký nên được ưu tiên để gỡ lỗi thông tin, cảnh báo, thông báo lỗi hoặc bất kỳ
thời gian bạn muốn dễ dàng nhận được thông báo nhanh từ các tập lệnh hoặc mô hình của mình.

Hiện tại có bảy cấp độ của thông điệp nhật ký về độ dài ngày càng tăng được xác định trong
hệ thống.

· LOG_ERROR --- Thông báo lỗi nhật ký (macro liên quan: NS_LOG_ERROR);

· LOG_WARN --- Thông báo cảnh báo nhật ký (macro liên quan: NS_LOG_WARN);

· LOG_DEBUG --- Ghi nhật ký thông báo gỡ lỗi tương đối hiếm, đặc biệt (macro liên quan:
NS_LOG_DEBUG);

· LOG_INFO --- Ghi nhật ký thông báo thông tin về tiến trình chương trình (macro liên quan:
NS_LOG_INFO);

· LOG_FUNCTION --- Ghi nhật ký thông báo mô tả từng hàm được gọi (hai macro được liên kết:
NS_LOG_FUNCTION, được sử dụng cho các hàm thành viên và NS_LOG_FUNCTION_NOARGS, được sử dụng cho tĩnh
chức năng);

· LOG_LOGIC - Thông báo nhật ký mô tả luồng logic bên trong một hàm (macro liên quan:
NS_LOG_LOGIC);

· LOG_ALL --- Ghi nhật ký mọi thứ được đề cập ở trên (không có macro liên quan).

Đối với mỗi LOG_TYPE, cũng có LOG_LEVEL_TYPE, nếu được sử dụng, cho phép ghi lại tất cả
cấp trên nó ngoài cấp của nó. (Do đó, LOG_ERROR và
LOG_LEVEL_ERROR và cả LOG_ALL và LOG_LEVEL_ALL đều tương đương về mặt chức năng.) Cho
ví dụ, việc bật LOG_INFO sẽ chỉ bật các thông báo được cung cấp bởi macro NS_LOG_INFO, trong khi
bật LOG_LEVEL_INFO cũng sẽ bật các thông báo được cung cấp bởi NS_LOG_DEBUG, NS_LOG_WARN
và macro NS_LOG_ERROR.

Chúng tôi cũng cung cấp macro ghi nhật ký vô điều kiện luôn được hiển thị, bất kể
cấp độ ghi nhật ký hoặc lựa chọn thành phần.

· NS_LOG_UNCOND - Ghi tin nhắn được liên kết vô điều kiện (không có cấp độ nhật ký liên quan).

Mỗi cấp độ có thể được yêu cầu đơn lẻ hoặc tích lũy; và ghi nhật ký có thể được thiết lập bằng cách sử dụng
biến môi trường shell (NS_LOG) hoặc bằng cách ghi nhật ký lệnh gọi hàm hệ thống. Như đã thấy
trước đó trong hướng dẫn, hệ thống ghi nhật ký có tài liệu Doxygen và bây giờ sẽ là
thời gian tốt để xem xét tài liệu Mô-đun ghi nhật ký nếu bạn chưa làm như vậy.

Bây giờ bạn đã đọc tài liệu rất chi tiết, hãy sử dụng một số kiến ​​thức đó
để có được một số thông tin thú vị từ cào / myfirst.cc kịch bản mẫu mà bạn có
đã được xây dựng.

Cho phép Logging
Hãy sử dụng biến môi trường NS_LOG để bật thêm một số ghi nhật ký, nhưng trước tiên, chỉ để
nhận được sự hỗ trợ của chúng tôi, hãy tiếp tục và chạy tập lệnh cuối cùng giống như bạn đã làm trước đó,

$ ./waf --run cào / myfirst

Bạn sẽ thấy đầu ra quen thuộc của phần đầu tiên ns-3 chương trình ví dụ

$ Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.413 giây)
Đã gửi 1024 byte tới 10.1.1.2
Đã nhận 1024 byte từ 10.1.1.1
Đã nhận 1024 byte từ 10.1.1.2

Nó chỉ ra rằng các thông báo "Đã gửi" và "Đã nhận" mà bạn thấy ở trên thực sự đang ghi nhật ký
tin nhắn từ Ứng dụng UdpEchoClientỨng dụng UdpEchoServer. Chúng tôi có thể hỏi
ứng dụng khách, ví dụ, để in thêm thông tin bằng cách đặt cấp độ ghi nhật ký của nó
thông qua biến môi trường NS_LOG.

Từ đây tôi sẽ giả định rằng bạn đang sử dụng một vỏ giống như sh sử dụng
cú pháp "VARIABLE = value". Nếu bạn đang sử dụng một trình bao giống như csh, thì bạn sẽ phải
chuyển đổi các ví dụ của tôi thành cú pháp "setenv VARIABLE value" được yêu cầu bởi các trình bao đó.

Ngay bây giờ, ứng dụng khách UDP echo đang phản hồi dòng mã sau trong
cào / myfirst.cc,

LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);

Dòng mã này cho phép LOG_LEVEL_INFO mức độ ghi nhật ký. Khi chúng tôi vượt qua một bản ghi
cờ cấp, chúng tôi thực sự đang bật cấp đã cho và tất cả các cấp thấp hơn. Trong trường hợp này,
chúng tôi đã kích hoạt NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARNNS_LOG_ERROR. Chúng tôi có thể tăng
cấp độ ghi nhật ký và nhận thêm thông tin mà không cần thay đổi tập lệnh và biên dịch lại bằng cách
thiết lập biến môi trường NS_LOG như thế này:

$ export NS_LOG = UdpEchoClientApplication = level_all

Điều này đặt biến môi trường shell NS_LOG vào chuỗi,

UdpEchoClientApplication = level_all

Phía bên trái của bài tập là tên của thành phần ghi nhật ký mà chúng tôi muốn đặt,
và phía bên tay phải là lá cờ mà chúng tôi muốn sử dụng. Trong trường hợp này, chúng tôi sẽ bật
tất cả các cấp độ gỡ lỗi cho ứng dụng. Nếu bạn chạy tập lệnh với bộ NS_LOG
theo cách này, ns-3 hệ thống ghi nhật ký sẽ nhận thay đổi và bạn sẽ thấy như sau
đầu ra:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.404 giây)
UdpEchoClientApplication: UdpEchoClient ()
Ứng dụng UdpEchoClient:SetDataSize(1024)
UdpEchoClientApplication: StartApplication ()
UdpEchoClientApplication: ScheduleTransmit ()
UdpEchoClientApplication: Gửi ()
Đã gửi 1024 byte tới 10.1.1.2
Đã nhận 1024 byte từ 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Đã nhận 1024 byte từ 10.1.1.2
UdpEchoClientApplication: StopApplication ()
UdpEchoClientApplication: DoDispose ()
UdpEchoClientApplication: ~ UdpEchoClient ()

Thông tin gỡ lỗi bổ sung do ứng dụng cung cấp là từ NS_LOG_FUNCTION
cấp độ. Điều này hiển thị mỗi khi một hàm trong ứng dụng được gọi trong tập lệnh
chấp hành. Nói chung, việc sử dụng (ít nhất) NS_LOG_FUNCTION (cái này) trong các hàm thành viên là
được ưu tiên. Chỉ sử dụng NS_LOG_FUNCTION_NOARGS () trong các hàm tĩnh. Tuy nhiên, lưu ý rằng
không có yêu cầu trong ns-3 hệ thống mà các mô hình phải hỗ trợ bất kỳ
chức năng ghi nhật ký. Quyết định về lượng thông tin được ghi lại là để
nhà phát triển mô hình cá nhân. Trong trường hợp của các ứng dụng echo, rất nhiều bản ghi
đầu ra có sẵn.

Bây giờ bạn có thể xem nhật ký của các lệnh gọi hàm đã được thực hiện cho ứng dụng. nếu bạn
nhìn kỹ, bạn sẽ nhận thấy một dấu hai chấm giữa chuỗi Ứng dụng UdpEchoClient
và tên phương thức mà bạn có thể mong đợi một toán tử phạm vi C ++ (::). Đây là
có chủ đích.

Tên thực sự không phải là tên lớp, nó là tên thành phần ghi nhật ký. Khi có một
sự tương ứng XNUMX-XNUMX giữa một tệp nguồn và một lớp, điều này thường sẽ là
tên lớp nhưng bạn nên hiểu rằng nó thực sự không phải là tên lớp, và có một
dấu hai chấm đơn ở đó thay vì dấu hai chấm để nhắc nhở bạn một cách tương đối tinh tế để
tách biệt khái niệm tên thành phần ghi nhật ký khỏi tên lớp.

Nó chỉ ra rằng trong một số trường hợp, có thể khó xác định phương pháp nào thực sự
tạo một thông báo nhật ký. Nếu bạn nhìn vào văn bản ở trên, bạn có thể tự hỏi nơi chuỗi
"Nhận được 1024 byte từ 10.1.1.2"đến từ. Bạn có thể giải quyết vấn đề này bằng cách HOẶC
tiền tố_func cấp vào NS_LOG biến môi trường. Hãy thử làm như sau,

$ export 'NS_LOG = UdpEchoClientApplication = level_all | prefix_func'

Lưu ý rằng dấu ngoặc kép là bắt buộc vì thanh dọc chúng tôi sử dụng để biểu thị HOẶC
hoạt động cũng là một đầu nối ống Unix.

Bây giờ, nếu bạn chạy tập lệnh, bạn sẽ thấy rằng hệ thống ghi nhật ký đảm bảo rằng mọi
thông báo từ thành phần nhật ký đã cho được đặt trước tên thành phần.

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.417 giây)
UdpEchoClientApplication: UdpEchoClient ()
Ứng dụng UdpEchoClient:SetDataSize(1024)
UdpEchoClientApplication: StartApplication ()
UdpEchoClientApplication: ScheduleTransmit ()
UdpEchoClientApplication: Gửi ()
UdpEchoClientApplication: Send (): Đã gửi 1024 byte đến 10.1.1.2
Đã nhận 1024 byte từ 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.2
UdpEchoClientApplication: StopApplication ()
UdpEchoClientApplication: DoDispose ()
UdpEchoClientApplication: ~ UdpEchoClient ()

Bây giờ bạn có thể thấy tất cả các thông báo đến từ ứng dụng khách UDP echo là
được xác định như vậy. Thông báo "Đã nhận 1024 byte từ 10.1.1.2" hiện rõ ràng
được xác định là đến từ ứng dụng máy khách echo. Tin nhắn còn lại phải là
đến từ ứng dụng máy chủ tiếng vang UDP. Chúng tôi có thể kích hoạt thành phần đó bằng cách nhập
danh sách các thành phần được phân tách bằng dấu hai chấm trong biến môi trường NS_LOG.

$ export 'NS_LOG = UdpEchoClientApplication = level_all | prefix_func:
UdpEchoServerApplication = level_all | prefix_func '

Cảnh báo: Bạn sẽ cần xóa dòng mới sau : trong văn bản ví dụ ở trên,
chỉ ở đó cho mục đích định dạng tài liệu.

Bây giờ, nếu bạn chạy tập lệnh, bạn sẽ thấy tất cả các thông báo nhật ký từ cả ứng dụng khách echo
và các ứng dụng máy chủ. Bạn có thể thấy rằng điều này có thể rất hữu ích trong việc gỡ lỗi các vấn đề.

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.406 giây)
UdpEchoServerApplication: UdpEchoServer ()
UdpEchoClientApplication: UdpEchoClient ()
Ứng dụng UdpEchoClient:SetDataSize(1024)
UdpEchoServerApplication: StartApplication ()
UdpEchoClientApplication: StartApplication ()
UdpEchoClientApplication: ScheduleTransmit ()
UdpEchoClientApplication: Gửi ()
UdpEchoClientApplication: Send (): Đã gửi 1024 byte đến 10.1.1.2
UdpEchoServerApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.1
UdpEchoServerApplication: HandleRead (): Echoing gói
UdpEchoClientApplication: HandleRead (0x624920, 0x625160)
UdpEchoClientApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.2
UdpEchoServerApplication: StopApplication ()
UdpEchoClientApplication: StopApplication ()
UdpEchoClientApplication: DoDispose ()
UdpEchoServerApplication: DoDispose ()
UdpEchoClientApplication: ~ UdpEchoClient ()
UdpEchoServerApplication: ~ UdpEchoServer ()

Đôi khi nó cũng hữu ích khi có thể xem thời gian mô phỏng mà tại đó một thông báo nhật ký
được tạo ra. Bạn có thể thực hiện việc này bằng cách OR trong bit prefix_time.

$ export 'NS_LOG = UdpEchoClientApplication = level_all | prefix_func | prefix_time:
UdpEchoServerApplication = level_all | prefix_func | prefix_time '

Một lần nữa, bạn sẽ phải xóa dòng mới ở trên. Nếu bạn chạy tập lệnh bây giờ, bạn nên
xem kết quả sau:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.418 giây)
0s UdpEchoServerApplication: UdpEchoServer ()
0s UdpEchoClientỨng dụng: UdpEchoClient ()
0s UdpEchoClientỨng dụng:SetDataSize(1024)
1s UdpEchoServerApplication: StartApplication ()
2s UdpEchoClientApplication: StartApplication ()
2s UdpEchoClientApplication: ScheduleTransmit ()
2s UdpEchoClientApplication: Send ()
2s UdpEchoClientApplication: Send (): Đã gửi 1024 byte tới 10.1.1.2
2.00369 giây UdpEchoServerApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.1
2.00369 giây UdpEchoServerApplication: HandleRead (): Echoing gói
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737 giây UdpEchoClientApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.2
10 giây UdpEchoServerApplication: StopApplication ()
10 giây UdpEchoClientApplication: StopApplication ()
UdpEchoClientApplication: DoDispose ()
UdpEchoServerApplication: DoDispose ()
UdpEchoClientApplication: ~ UdpEchoClient ()
UdpEchoServerApplication: ~ UdpEchoServer ()

Bạn có thể thấy rằng hàm tạo cho UdpEchoServer đã được gọi tại thời điểm mô phỏng
0 giây. Điều này thực sự xảy ra trước khi mô phỏng bắt đầu, nhưng thời gian là
hiển thị dưới dạng không giây. Điều này cũng đúng với thông báo phương thức khởi tạo UdpEchoClient.

Nhớ lại rằng cào / đầu tiên.cc script đã khởi động ứng dụng máy chủ echo sau một giây
vào mô phỏng. Bây giờ bạn có thể thấy rằng Bắt đầuỨng dụng phương thức của máy chủ là,
trên thực tế, được gọi là một giây. Bạn cũng có thể thấy rằng ứng dụng máy khách echo là
bắt đầu ở thời gian mô phỏng hai giây như chúng tôi yêu cầu trong tập lệnh.

Bây giờ bạn có thể theo dõi tiến trình của mô phỏng từ Lịch trìnhTruyền gọi trong
khách hàng gọi Gửi đến xử lýĐọc gọi lại trong ứng dụng máy chủ tiếng vọng. Ghi chú
rằng thời gian trôi qua để gói được gửi qua liên kết điểm-điểm là 3.69
mili giây. Bạn thấy máy chủ phản hồi ghi lại một thông báo cho bạn biết rằng nó đã bị dội lại
gói tin và sau đó, sau một thời gian trễ kênh khác, bạn thấy máy khách echo nhận được
gói được lặp lại trong nó xử lýĐọc phương pháp.

Có rất nhiều điều đang xảy ra dưới vỏ bọc trong mô phỏng này mà bạn không
nhìn thấy là tốt. Bạn có thể dễ dàng theo dõi toàn bộ quá trình bằng cách bật tất cả
ghi nhật ký các thành phần trong hệ thống. Hãy thử thiết lập NS_LOG biến thành sau đây,

$ export 'NS_LOG = * = level_all | prefix_func | prefix_time'

Dấu hoa thị ở trên là ký tự đại diện của thành phần ghi nhật ký. Điều này sẽ bật tất cả
đăng nhập tất cả các thành phần được sử dụng trong mô phỏng. Tôi sẽ không tái tạo đầu ra
ở đây (kể từ lúc viết bài này, nó tạo ra 1265 dòng đầu ra cho một gói dữ liệu duy nhất) nhưng
bạn có thể chuyển hướng thông tin này thành một tệp và xem qua nó với mục yêu thích của bạn
biên tập viên nếu bạn thích,

$ ./waf --run xước / myfirst> log.out 2> & 1

Cá nhân tôi sử dụng phiên bản ghi nhật ký cực kỳ dài dòng này khi tôi được trình bày với
vấn đề và tôi không biết mọi thứ đang diễn ra sai ở đâu. Tôi có thể theo dõi tiến trình của
mã khá dễ dàng mà không cần phải đặt các điểm ngắt và chuyển qua mã trong trình gỡ lỗi.
Tôi chỉ có thể chỉnh sửa kết quả đầu ra trong trình chỉnh sửa yêu thích của mình và tìm kiếm những thứ tôi mong đợi,
và xem những điều xảy ra mà tôi không mong đợi. Khi tôi có một ý tưởng chung về những gì
bị sai, tôi chuyển sang trình gỡ lỗi để kiểm tra chi tiết vấn đề.
Loại đầu ra này có thể đặc biệt hữu ích khi tập lệnh của bạn thực hiện một cách hoàn chỉnh
bất ngờ. Nếu bạn đang sử dụng trình gỡ lỗi, bạn có thể bỏ lỡ một chuyến tham quan bất ngờ
hoàn toàn. Ghi nhật ký chuyến tham quan giúp bạn có thể nhanh chóng nhìn thấy nó.

Thêm Logging đến qua một vài thao tác đơn giản về
Bạn có thể thêm ghi nhật ký mới vào mô phỏng của mình bằng cách thực hiện các cuộc gọi đến thành phần nhật ký qua
một số macro. Hãy làm như vậy trong myfirst.cc kịch bản chúng tôi có trong xước thư mục.

Nhớ lại rằng chúng ta đã xác định một thành phần ghi nhật ký trong tập lệnh đó:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Bây giờ bạn biết rằng bạn có thể bật tất cả ghi nhật ký cho thành phần này bằng cách thiết lập
NS_LOG môi trường biến thành các cấp độ khác nhau. Hãy tiếp tục và thêm một số ghi nhật ký vào
kịch bản. Macro được sử dụng để thêm thông báo nhật ký mức thông tin là NS_LOG_INFO. Đi
phía trước và thêm một (ngay trước khi chúng tôi bắt đầu tạo các nút) cho bạn biết rằng tập lệnh
là "Tạo cấu trúc liên kết." Điều này được thực hiện như trong đoạn mã này,

Mở cào / myfirst.cc trong trình chỉnh sửa yêu thích của bạn và thêm dòng,

NS_LOG_INFO ("Tạo cấu trúc liên kết");

ngay trước các dòng,

Các nút NodeContainer;
các nút.Create (2);

Bây giờ, hãy xây dựng tập lệnh bằng cách sử dụng waf và xóa NS_LOG biến để tắt torrent của
ghi nhật ký chúng tôi đã bật trước đây:

$ ./waf
$ export NS_LOG =

Bây giờ, nếu bạn chạy tập lệnh,

$ ./waf --run cào / myfirst

bạn sẽ không xem tin nhắn mới của bạn kể từ thành phần ghi nhật ký liên quan của nó
(FirstScriptVí dụ) chưa được kích hoạt. Để xem tin nhắn của bạn, bạn sẽ phải
cho phép FirstScriptVí dụ thành phần ghi nhật ký có cấp độ lớn hơn hoặc bằng
NS_LOG_INFO. Nếu bạn chỉ muốn xem mức độ ghi nhật ký cụ thể này, bạn có thể bật nó
bởi,

$ export NS_LOG = FirstScriptExample = thông tin

Nếu bây giờ bạn chạy tập lệnh, bạn sẽ thấy thông báo nhật ký "Tạo cấu trúc liên kết" mới của mình,

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.404 giây)
Tạo cấu trúc liên kết
Đã gửi 1024 byte tới 10.1.1.2
Đã nhận 1024 byte từ 10.1.1.1
Đã nhận 1024 byte từ 10.1.1.2

Sử dụng Lệnh Dòng Lập luận
Ghi đè Mặc định Thuộc tính
Một cách khác, bạn có thể thay đổi cách thức ns-3 tập lệnh hoạt động mà không cần chỉnh sửa và việc xây dựng được thực hiện thông qua
lệnh hàng lập luận. Chúng tôi cung cấp một cơ chế để phân tích cú pháp các đối số dòng lệnh và
tự động đặt các biến cục bộ và toàn cục dựa trên các đối số đó.

Bước đầu tiên trong việc sử dụng hệ thống đối số dòng lệnh là khai báo dòng lệnh
trình phân tích cú pháp. Điều này được thực hiện khá đơn giản (trong chương trình chính của bạn) như trong đoạn mã sau,

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

Dòng lệnh cmd;
cmd.Parse(argc, argv);

...
}

Đoạn mã hai dòng đơn giản này thực sự rất hữu ích. Nó mở ra cánh cửa dẫn đến
ns-3 biến toàn cục và đặc tính các hệ thống. Hãy tiếp tục và thêm hai dòng mã đó vào
các cào / myfirst.cc kịch bản ở đầu chính. Hãy tiếp tục và xây dựng tập lệnh và chạy
nó, nhưng hãy yêu cầu tập lệnh trợ giúp theo cách sau,

$ ./waf --run "xước / myfirst --PrintHelp"

Điều này sẽ yêu cầu Waf chạy vết xước / đầu tiên script và chuyển đối số dòng lệnh
--PrintTrợ giúp vào tập lệnh. Các dấu ngoặc kép được yêu cầu để phân loại chương trình nào nhận được
lý lẽ. Trình phân tích cú pháp dòng lệnh bây giờ sẽ thấy --PrintTrợ giúp tranh luận và trả lời bằng,

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.413 giây)
TcpL4Protocol: TcpStateMachine ()
CommandLine: HandleArgument (): Tên đối số xử lý = Giá trị PrintHelp =
--PrintHelp: In thông báo trợ giúp này.
--PrintGroups: In danh sách các nhóm.
--PrintTypeIds: In tất cả các TypeIds.
--PrintGroup = [group]: In tất cả các TypeIds của nhóm.
--PrintAttributes = [typeid]: In tất cả các thuộc tính của typeid.
--PrintGlobals: In danh sách các hình cầu.

Hãy tập trung vào --Thuộc tính in lựa chọn. Chúng tôi đã gợi ý về ns-3 đặc tính
hệ thống trong khi đi qua đầu tiên.cc script. Chúng tôi đã xem xét các dòng sau của
mã,

PointToPointTrợ giúp pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

và đề cập rằng Tốc độ dữ liệu thực sự là một đặc tính của PointToPointNetThiết bị. Hãy
sử dụng trình phân tích cú pháp đối số dòng lệnh để xem Thuộc tính của
PointToPointNetDevice. Danh sách trợ giúp nói rằng chúng tôi nên cung cấp một loạiId. Điều này
tương ứng với tên lớp của lớp mà Thuộc tính thuộc về. Trong trường hợp này
nó sẽ là ns3 :: PointToPointNetDevice. Hãy tiếp tục và nhập,

$ ./waf --run "xước / myfirst --PrintAttributes = ns3 :: PointToPointNetDevice"

Hệ thống sẽ in ra tất cả Thuộc tính của loại thiết bị mạng này. Trong sô
Thuộc tính bạn sẽ thấy được liệt kê là,

--ns3 :: PointToPointNetDevice :: DataRate = [32768bps]:
Tốc độ dữ liệu mặc định cho các liên kết điểm tới điểm

Đây là giá trị mặc định sẽ được sử dụng khi PointToPointNetThiết bị được tạo ra trong
hệ thống. Chúng tôi ghi đè mặc định này với đặc tính thiết lập trong PointToPointTrợ giúp
bên trên. Hãy sử dụng các giá trị mặc định cho các thiết bị và kênh điểm-điểm bằng cách
xóa SetDeviceAttribution cuộc gọi và SetChannelAttribution cuộc gọi từ myfirst.cc
chúng tôi có trong thư mục đầu.

Tập lệnh của bạn bây giờ chỉ cần khai báo PointToPointTrợ giúp và không làm bất kỳ định hoạt động
như trong ví dụ sau,

...

Các nút NodeContainer;
các nút.Create (2);

PointToPointTrợ giúp pointToPoint;

Thiết bị NetDeviceContainer;
thiết bị = pointToPoint.Install (các nút);

...

Hãy tiếp tục và xây dựng tập lệnh mới với Waf (./waff) và hãy quay lại và bật một số
ghi nhật ký từ ứng dụng máy chủ tiếng vang UDP và bật tiền tố thời gian.

$ export 'NS_LOG = UdpEchoServerApplication = level_all | prefix_time'

Nếu bạn chạy tập lệnh, bây giờ bạn sẽ thấy kết quả sau:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.405 giây)
0s UdpEchoServerApplication: UdpEchoServer ()
1s UdpEchoServerApplication: StartApplication ()
Đã gửi 1024 byte tới 10.1.1.2
2.25732 giây Nhận 1024 byte từ 10.1.1.1
Gói tiếng vọng 2.25732 giây
Đã nhận 1024 byte từ 10.1.1.2
10 giây UdpEchoServerApplication: StopApplication ()
UdpEchoServerApplication: DoDispose ()
UdpEchoServerApplication: ~ UdpEchoServer ()

Nhớ lại rằng lần cuối cùng chúng ta xem xét thời gian mô phỏng mà tại đó gói tin
do máy chủ phản hồi nhận được, tốc độ là 2.00369 giây.

2.00369 giây UdpEchoServerApplication: HandleRead (): Đã nhận 1024 byte từ 10.1.1.1

Bây giờ nó đang nhận được gói tin với tốc độ 2.25732 giây. Điều này là do chúng tôi vừa bỏ
tốc độ dữ liệu của PointToPointNetThiết bị xuống mặc định là 32768 bit mỗi giây từ
năm megabit mỗi giây.

Nếu chúng tôi cung cấp một Tốc độ dữ liệu bằng cách sử dụng dòng lệnh, chúng tôi có thể tăng tốc độ mô phỏng của mình
lên một lần nữa. Chúng tôi làm điều này theo cách sau đây, theo công thức được ngụ ý bởi sự trợ giúp
mục:

$ ./waf --run "xước / myfirst --ns3 :: PointToPointNetDevice :: DataRate = 5Mbps"

Điều này sẽ đặt giá trị mặc định của Tốc độ dữ liệu đặc tính trở lại năm megabit mỗi
thứ hai. Bạn có ngạc nhiên về kết quả này không? Nó chỉ ra rằng để có được bản gốc
hành vi của tập lệnh trở lại, chúng tôi sẽ phải đặt độ trễ tốc độ ánh sáng của kênh
cũng. Chúng ta có thể yêu cầu hệ thống dòng lệnh in ra Thuộc tính của kênh
giống như chúng tôi đã làm cho thiết bị net:

$ ./waf --run "xước / myfirst --PrintAttributes = ns3 :: PointToPointChannel"

Chúng tôi phát hiện ra chậm trễ đặc tính của kênh được đặt theo cách sau:

--ns3 :: PointToPointChannel :: Delay = [0ns]:
Trễ truyền qua kênh

Sau đó, chúng tôi có thể đặt cả hai giá trị mặc định này thông qua hệ thống dòng lệnh,

$ ./waf --run "cào / myfirst
--ns3 :: PointToPointNetDevice :: DataRate = 5Mbps
--ns3 :: PointToPointChannel :: Delay = 2ms "

trong trường hợp đó, chúng tôi khôi phục thời gian mà chúng tôi đã có khi chúng tôi đặt Tốc độ dữ liệuchậm trễ
trong kịch bản:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.417 giây)
0s UdpEchoServerApplication: UdpEchoServer ()
1s UdpEchoServerApplication: StartApplication ()
Đã gửi 1024 byte tới 10.1.1.2
2.00369 giây Nhận 1024 byte từ 10.1.1.1
Gói tiếng vọng 2.00369 giây
Đã nhận 1024 byte từ 10.1.1.2
10 giây UdpEchoServerApplication: StopApplication ()
UdpEchoServerApplication: DoDispose ()
UdpEchoServerApplication: ~ UdpEchoServer ()

Lưu ý rằng gói tin được máy chủ nhận lại ở giây thứ 2.00369. Chúng ta có thể
thực sự thiết lập bất kỳ Thuộc tính được sử dụng trong kịch bản theo cách này. Đặc biệt chúng tôi có thể
thiết lập UdpEchoClient đặc tính Gói tối đa sang một số giá trị khác hơn một giá trị.

Làm thế nào bạn sẽ đi về điều đó? Hãy thử một lần. Hãy nhớ rằng bạn phải bình luận về nơi này
chúng tôi ghi đè mặc định đặc tính và thiết lập rõ ràng Gói tối đa trong kịch bản. Sau đó bạn
phải xây dựng lại kịch bản. Bạn cũng sẽ phải tìm cú pháp để thực sự thiết lập
giá trị thuộc tính mặc định mới bằng cách sử dụng phương tiện trợ giúp dòng lệnh. Một khi bạn có cái này
tìm ra rằng bạn sẽ có thể kiểm soát số lượng các gói được gửi lại từ lệnh
hàng. Vì chúng tôi là những người tốt, chúng tôi sẽ cho bạn biết rằng dòng lệnh của bạn sẽ kết thúc
cái gì đó như,

$ ./waf --run "cào / myfirst
--ns3 :: PointToPointNetDevice :: DataRate = 5Mbps
--ns3 :: PointToPointChannel :: Delay = 2ms
--ns3 :: UdpEchoClient :: MaxPackets = 2 "

Câu chuyện trên màn hình Riêng Các giá trị
Bạn cũng có thể thêm các hook của riêng mình vào hệ thống dòng lệnh. Điều này được thực hiện khá đơn giản bằng cách
bằng cách sử dụng Thêm giá trị đến trình phân tích cú pháp dòng lệnh.

Hãy sử dụng cơ sở này để chỉ định số lượng gói dữ liệu để lặp lại trong một hoàn toàn khác
đường. Hãy thêm một biến cục bộ được gọi là nGói đến chính chức năng. Chúng tôi sẽ khởi tạo
nó thành một để phù hợp với hành vi mặc định trước đây của chúng tôi. Để cho phép trình phân tích cú pháp dòng lệnh
thay đổi giá trị này, chúng ta cần nối giá trị vào trình phân tích cú pháp. Chúng tôi thực hiện điều này bằng cách thêm một cuộc gọi
đến Thêm giá trị. Hãy tiếp tục và thay đổi cào / myfirst.cc kịch bản để bắt đầu với
mã sau,

int
main (int argc, char * argv [])
{
uint32_t nGói = 1;

Dòng lệnh cmd;
cmd.AddValue ("nPackets", "Số lượng gói để echo", nPackets);
cmd.Parse(argc, argv);

...

Cuộn xuống điểm trong tập lệnh nơi chúng tôi đặt Gói tối đa đặc tính và thay đổi nó
để nó được đặt thành biến nGói thay vì hằng số 1 như được hiển thị bên dưới.

echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));

Bây giờ nếu bạn chạy tập lệnh và cung cấp --PrintTrợ giúp tranh luận, bạn sẽ thấy
người sử dang Tranh luận được liệt kê trong màn hình trợ giúp.

Thử,

$ ./waf --run "xước / myfirst --PrintHelp"

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.403 giây)
--PrintHelp: In thông báo trợ giúp này.
--PrintGroups: In danh sách các nhóm.
--PrintTypeIds: In tất cả các TypeIds.
--PrintGroup = [group]: In tất cả các TypeIds của nhóm.
--PrintAttributes = [typeid]: In tất cả các thuộc tính của typeid.
--PrintGlobals: In danh sách các hình cầu.
Đối số của người dùng:
--nPackets: Số lượng gói dữ liệu để lặp lại

Nếu bạn muốn chỉ định số lượng gói tin sẽ lặp lại, bây giờ bạn có thể làm như vậy bằng cách thiết lập
--nGói đối số trong dòng lệnh,

$ ./waf --run "xước / myfirst --nPackets = 2"

Bây giờ bạn sẽ thấy

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.404 giây)
0s UdpEchoServerApplication: UdpEchoServer ()
1s UdpEchoServerApplication: StartApplication ()
Đã gửi 1024 byte tới 10.1.1.2
2.25732 giây Nhận 1024 byte từ 10.1.1.1
Gói tiếng vọng 2.25732 giây
Đã nhận 1024 byte từ 10.1.1.2
Đã gửi 1024 byte tới 10.1.1.2
3.25732 giây Nhận 1024 byte từ 10.1.1.1
Gói tiếng vọng 3.25732 giây
Đã nhận 1024 byte từ 10.1.1.2
10 giây UdpEchoServerApplication: StopApplication ()
UdpEchoServerApplication: DoDispose ()
UdpEchoServerApplication: ~ UdpEchoServer ()

Bây giờ bạn đã lặp lại hai gói tin. Khá dễ dàng phải không?

Bạn có thể thấy điều đó nếu bạn là một ns-3 người dùng, bạn có thể sử dụng hệ thống đối số dòng lệnh để
kiểm soát các giá trị toàn cầu và Thuộc tính. Nếu bạn là tác giả mô hình, bạn có thể thêm mới
Thuộc tính để của bạn Đối tượng và chúng sẽ tự động có sẵn để cài đặt bởi
người dùng thông qua hệ thống dòng lệnh. Nếu bạn là tác giả kịch bản, bạn có thể thêm mới
biến các tập lệnh của bạn và kết nối chúng vào hệ thống dòng lệnh một cách dễ dàng.

Sử dụng các Truy tìm WELFARE
Toàn bộ điểm của mô phỏng là tạo ra đầu ra để nghiên cứu thêm, và ns-3
hệ thống truy tìm là một cơ chế chính cho việc này. Từ ns-3 là một chương trình C ++, tiêu chuẩn
Có thể sử dụng các phương tiện để tạo đầu ra từ các chương trình C ++:

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

Bạn thậm chí có thể sử dụng mô-đun ghi nhật ký để thêm một cấu trúc nhỏ vào giải pháp của mình. Ở đó
nhiều vấn đề nổi tiếng được tạo ra bởi các cách tiếp cận như vậy và vì vậy chúng tôi đã cung cấp
hệ thống con theo dõi sự kiện chung để giải quyết các vấn đề mà chúng tôi cho là quan trọng.

Các mục tiêu cơ bản của ns-3 hệ thống truy tìm là:

· Đối với các tác vụ cơ bản, hệ thống theo dõi phải cho phép người dùng tạo ra theo dõi tiêu chuẩn
cho các nguồn truy tìm phổ biến và để tùy chỉnh đối tượng nào tạo ra truy tìm;

· Người dùng trung gian phải có khả năng mở rộng hệ thống theo dõi để sửa đổi định dạng đầu ra
được tạo hoặc để chèn các nguồn theo dõi mới 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ản phẩm 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à
theo dấu vết chìm và một cơ chế thống nhất để kết nối các nguồn với phần chìm. 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 quyền 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 một gói
nhận được 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 để theo dõi quan tâm
chìm.

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 phần khác của
mã thực sự làm điều gì đó hữu ích với thông tin được cung cấp bởi bồn rửa. Dấu vết
chìm là người tiêu thụ các sự kiện và dữ liệu được cung cấp bởi các nguồn theo dõi. Ví dụ,
người ta có thể tạo ra một bể theo dõi sẽ (khi được kết nối với nguồn theo dõi của
ví dụ trước) in ra các phần thú vị của gói đã nhận.

Cơ sở lý luận cho sự phân chia rõ ràng này là cho phép người dùng 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 yêu cầu chỉnh sửa và biên dịch lại phần cốt lõi của
giả lập. Do đó, trong ví dụ trên, người dùng có thể xác định một rãnh theo dõi mới trong
script và đính kèm nó vào nguồn theo dõi hiện có được xác định trong lõi mô phỏng bằng cách
chỉ chỉnh sửa tập lệnh người dùng.

Trong hướng dẫn này, chúng tôi sẽ đi qua một số nguồn và phần chìm được xác định trước và chỉ ra cách
chúng có thể được tùy chỉnh với ít nỗ lực của người dùng. Xem hướng dẫn sử dụng ns-3 hoặc các phần hướng dẫn
để biết thông tin về cấu hình theo dõi nâng cao bao gồm cả việc mở rộng theo dõi
không gian tên và tạo nguồn theo dõi mới.

ASCII Truy tìm
ns-3 cung cấp chức năng trợ giúp bao bọc hệ thống theo dõi cấp thấp để giúp bạn
với các chi tiết liên quan đến việc cấu hình một số dấu vết gói dễ hiểu. nếu bạn
kích hoạt chức năng này, bạn sẽ thấy đầu ra trong tệp ASCII --- do đó là tên. Vì
những người quen thuộc với ns-2 đầu ra, loại dấu vết này tương tự như ra.tr tạo ra
bằng nhiều tập lệnh.

Hãy bắt đầu ngay và thêm một số đầu ra theo dõi ASCII vào cào / myfirst.cc
script. Ngay trước cuộc gọi tới Trình mô phỏng :: Chạy (), thêm các dòng mã sau:

AsciiTraceTrợ giúp ascii;
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Giống như nhiều nơi khác ns-3 thành ngữ, mã này sử dụng một đối tượng trợ giúp để giúp tạo ASCII
dấu vết. Dòng thứ hai chứa hai lệnh gọi phương thức lồng nhau. Phương pháp "bên trong",
CreateFileStream () sử dụng một thành ngữ đối tượng không tên để tạo một đối tượng luồng tệp trên
ngăn xếp (không có tên đối tượng) và chuyển nó xuống phương thức được gọi. Chúng ta sẽ đi vào vấn đề này
nhiều hơn nữa trong tương lai, nhưng tất cả những gì bạn phải biết tại thời điểm này là bạn đang tạo
đối tượng đại diện cho một tệp có tên "myfirst.tr" và chuyển nó vào ns-3. Bạn đang nói
ns-3 để giải quyết các vấn đề tồn tại của đối tượng đã tạo và cũng để giải quyết các vấn đề
gây ra bởi một hạn chế ít được biết đến (có chủ ý) của các đối tượng trong dòng C ++ liên quan đến bản sao
các nhà xây dựng.

Cuộc gọi bên ngoài, để EnableAsciiAll (), cho người trợ giúp biết rằng bạn muốn bật ASCII
truy tìm trên tất cả các thiết bị điểm-điểm trong mô phỏng của bạn; và bạn muốn (được cung cấp)
dấu vết chìm để ghi thông tin về chuyển động của gói ở định dạng ASCII.

Đối với những người quen thuộc với ns-2, các sự kiện được theo dõi tương đương với các điểm theo dõi phổ biến
nhật ký các sự kiện "+", "-", "d" và "r".

Bây giờ bạn có thể xây dựng tập lệnh và chạy nó từ dòng lệnh:

$ ./waf --run cào / myfirst

Cũng như bạn đã thấy nhiều lần trước đây, bạn sẽ thấy một số thông báo từ Waf và sau đó
"" xây dựng "đã hoàn thành thành công" với một số thông báo từ chương trình đang chạy.

Khi nó chạy, chương trình sẽ tạo một tệp có tên myfirst.tr. Vì con đường
Waf hoạt động, tệp không được tạo trong thư mục cục bộ, nó được tạo tại
thư mục cấp cao nhất của kho lưu trữ theo mặc định. Nếu bạn muốn kiểm soát nơi có dấu vết
được cứu, bạn có thể sử dụng --cwd tùy chọn của Waf để chỉ định điều này. Chúng tôi đã không làm như vậy, do đó
chúng ta cần chuyển sang thư mục cấp cao nhất của kho lưu trữ của mình và xem ASCII
tập tin theo dõi myfirst.tr trong trình soạn thảo yêu thích của bạn.

Phân tích cú pháp Thăng thiên Dấu vết
Có rất nhiều thông tin ở đó dưới dạng khá dày đặc, nhưng điều đầu tiên cần chú ý
là có một số dòng riêng biệt trong tệp này. Có thể khó nhìn thấy
điều này rõ ràng trừ khi bạn mở rộng cửa sổ đáng kể.

Mỗi dòng trong tệp tương ứng với một theo dõi sự kiện. Trong trường hợp này, chúng tôi đang theo dõi các sự kiện trên
các truyền hàng đợi hiện diện trong mọi thiết bị net point-to-point trong mô phỏng. Các
hàng đợi truyền là một hàng đợi mà qua đó mọi gói được dành cho một kênh điểm-điểm
bắt buộc phải đậu. Lưu ý rằng mỗi dòng trong tệp theo dõi bắt đầu bằng một ký tự duy nhất (có
dấu cách sau nó). Ký tự này sẽ có ý nghĩa sau:

· +: Một hoạt động xếp hàng đã xảy ra trên hàng đợi thiết bị;

· -: Một hoạt động xếp hàng đã xảy ra trên hàng đợi thiết bị;

· d: Một gói tin đã bị loại bỏ, thường là do hàng đợi đã đầy;

· r: Một gói được nhận bởi thiết bị mạng.

Hãy xem chi tiết hơn về dòng đầu tiên trong tệp theo dõi. Tôi sẽ phá vỡ nó
thành các phần (được thụt lề để rõ ràng) với số tham chiếu ở phía bên trái:

+
2
/ NodeList / 0 / DeviceList / 0 / $ ns3 :: PointToPointNetDevice / TxQueue / Enqueue
ns3 :: PppHeader (
Giao thức điểm-điểm: IP (0x0021))
ns3 :: Ipv4Header (
tos 0x0 ttl 64 id 0 giao thức 17 bù đắp 0 cờ [không có]
chiều dài: 1052 10.1.1.1> 10.1.1.2)
ns3 :: UdpHeader (
chiều dài: 1032 49153> 9)
Tải trọng (kích thước = 1024)

Phần đầu tiên của sự kiện theo dõi mở rộng này (số tham chiếu 0) là hoạt động. chúng tôi
có một + ký tự, vì vậy điều này tương ứng với một enqueue hoạt động trên hàng đợi truyền.
Phần thứ hai (tài liệu tham khảo 1) là thời gian mô phỏng tính bằng giây. Bạn có thể
nhớ lại rằng chúng tôi đã hỏi Ứng dụng UdpEchoClient để bắt đầu gửi gói sau hai giây.
Ở đây chúng tôi thấy xác nhận rằng điều này thực sự đang xảy ra.

Phần tiếp theo của dấu vết mẫu (tài liệu tham khảo 2) cho chúng ta biết nguồn theo dõi nào bắt nguồn
sự kiện này (được thể hiện trong không gian tên truy tìm). Bạn có thể nghĩ về không gian tên truy tìm
phần nào giống như bạn làm với một không gian tên hệ thống tệp. Gốc của không gian tên là
Danh sách nút. Điều này tương ứng với một vùng chứa được quản lý trong ns-3 mã lõi chứa tất cả
của các nút được tạo trong một tập lệnh. Cũng giống như một hệ thống tệp có thể có các thư mục
dưới gốc, chúng ta có thể có số nút trong Danh sách nút. Chuỗi / NodeList / 0
do đó đề cập đến nút thứ XNUMX trong Danh sách nút mà chúng tôi thường nghĩ là "nút
0 ". Trong mỗi nút có một danh sách các thiết bị đã được cài đặt. Danh sách này xuất hiện
tiếp theo trong không gian tên. Bạn có thể thấy rằng sự kiện theo dõi này đến từ Danh sách thiết bị / 0 đó là
thiết bị thứ XNUMX được cài đặt trong nút.

Chuỗi tiếp theo, $ ns3 :: PointToPointNetDevice cho bạn biết loại thiết bị nào trong
vị trí thứ không của danh sách thiết bị cho nút số không. Nhớ lại rằng hoạt động + tìm thấy tại
tham chiếu 00 có nghĩa là một hoạt động xếp hàng đã xảy ra trên hàng đợi truyền của thiết bị.
Điều này được phản ánh trong các phân đoạn cuối cùng của "con đường theo dõi" là TxQueue / Enqueue.

Các phần còn lại trong dấu vết sẽ khá trực quan. Tài liệu tham khảo 3-4 cho biết
rằng gói được đóng gói trong giao thức điểm-điểm. Tài liệu tham khảo 5-7 cho thấy rằng
gói có tiêu đề IP phiên bản bốn và có nguồn gốc từ địa chỉ IP 10.1.1.1 và
được dành cho 10.1.1.2. Tài liệu tham khảo 8-9 cho thấy rằng gói tin này có tiêu đề UDP và,
cuối cùng, tham chiếu 10 cho thấy rằng tải trọng dự kiến ​​là 1024 byte.

Dòng tiếp theo trong tệp theo dõi hiển thị cùng một gói đang được định giá lại từ quá trình truyền
xếp hàng trên cùng một nút.

Dòng thứ ba trong tệp theo dõi cho biết gói đang được thiết bị mạng nhận trên
nút với máy chủ tiếng vọng. Tôi đã tái hiện sự kiện đó dưới đây.

r
2.25732
/ NodeList / 1 / DeviceList / 0 / $ ns3 :: PointToPointNetDevice / MacRx
ns3 :: Ipv4Header (
tos 0x0 ttl 64 id 0 giao thức 17 bù đắp 0 cờ [không có]
chiều dài: 1052 10.1.1.1> 10.1.1.2)
ns3 :: UdpHeader (
chiều dài: 1032 49153> 9)
Tải trọng (kích thước = 1024)

Lưu ý rằng thao tác theo dõi bây giờ là r và thời gian mô phỏng đã tăng lên 2.25732
giây. Nếu bạn đã làm theo các bước hướng dẫn chặt chẽ, điều này có nghĩa là bạn có
rời khỏi Tốc độ dữ liệu của các thiết bị mạng và kênh chậm trễ đặt thành giá trị mặc định của chúng.
Lần này sẽ quen thuộc như bạn đã từng thấy trong phần trước.

Mục nhập không gian tên nguồn theo dõi (tham chiếu 02) đã thay đổi để phản ánh rằng sự kiện này là
đến từ nút 1 (/ NodeList / 1) và nguồn theo dõi tiếp nhận gói tin (/ MacRx). Nó
sẽ khá dễ dàng để bạn theo dõi tiến trình của gói thông qua cấu trúc liên kết bằng cách
nhìn vào phần còn lại của dấu vết trong tệp.

PCAP Truy tìm
Sản phẩm ns-3 trình trợ giúp thiết bị cũng có thể được sử dụng để tạo các tệp theo dõi trong .pcap định dạng. Các
từ viết tắt pcap (thường được viết bằng chữ thường) là viết tắt của bắt gói và thực sự là một
API bao gồm định nghĩa của một .pcap định dạng tệp. Chương trình phổ biến nhất
có thể đọc và hiển thị định dạng này là Wireshark (trước đây gọi là Ethereal). Tuy nhiên, ở đó
nhiều máy phân tích theo dõi lưu lượng sử dụng định dạng gói này. Chúng tôi khuyến khích người dùng
khai thác nhiều công cụ có sẵn để phân tích dấu vết pcap. Trong hướng dẫn này, chúng tôi
tập trung vào việc xem dấu vết pcap với tcpdump.

Mã được sử dụng để kích hoạt tính năng theo dõi pcap là một đoạn mã.

pointToPoint.EnablePcapAll ("myfirst");

Hãy tiếp tục và chèn dòng mã này sau mã truy tìm ASCII mà chúng tôi vừa thêm vào
cào / myfirst.cc. Lưu ý rằng chúng tôi chỉ chuyển chuỗi "myfirst" chứ không phải
"myfirst.pcap" hoặc cái gì đó tương tự. Điều này là do tham số là tiền tố, không phải
tên tệp đầy đủ. Người trợ giúp sẽ thực sự tạo một tệp theo dõi cho mọi điểm
thiết bị trong mô phỏng. Tên tệp sẽ được tạo bằng cách sử dụng tiền tố, số nút,
số thiết bị và hậu tố ".pcap".

Trong tập lệnh mẫu của chúng tôi, cuối cùng chúng tôi sẽ thấy các tệp có tên "myfirst-0-0.pcap" và
"myfirst-1-0.pcap" là các dấu vết pcap cho nút 0-thiết bị 0 và nút 1-thiết bị 0,
tương ứng.

Khi bạn đã thêm dòng mã để bật tính năng theo dõi pcap, bạn có thể chạy tập lệnh trong
cách thông thường:

$ ./waf --run cào / myfirst

Nếu bạn nhìn vào thư mục cấp cao nhất của bản phân phối của mình, bây giờ bạn sẽ thấy ba nhật ký
các tập tin: myfirst.tr là tệp theo dõi ASCII mà chúng tôi đã kiểm tra trước đây. myfirst-0-0.pcap
myfirst-1-0.pcap là các tệp pcap mới mà chúng tôi vừa tạo.

Reading đầu ra với tcpdump
Điều dễ dàng nhất để làm tại thời điểm này là sử dụng tcpdump nhìn vào các tập tin.

$ tcpdump -nn -tt -r myfirst-0-0.pcap
đọc từ tệp myfirst-0-0.pcap, PPP kiểu liên kết (PPP)
2.000000 IP 10.1.1.1.49153> 10.1.1.2.9: UDP, chiều dài 1024
2.514648 IP 10.1.1.2.9> 10.1.1.1.49153: UDP, chiều dài 1024

tcpdump -nn -tt -r myfirst-1-0.pcap
đọc từ tệp myfirst-1-0.pcap, PPP kiểu liên kết (PPP)
2.257324 IP 10.1.1.1.49153> 10.1.1.2.9: UDP, chiều dài 1024
2.257324 IP 10.1.1.2.9> 10.1.1.1.49153: UDP, chiều dài 1024

Bạn có thể thấy trong bãi chứa của myfirst-0-0.pcap (thiết bị khách) mà gói tiếng vọng là
được gửi ở thời điểm 2 giây vào mô phỏng. Nếu bạn nhìn vào bãi chứa thứ hai (myfirst-1-0.pcap)
bạn có thể thấy gói đó đang được nhận với tốc độ 2.257324 giây. Bạn thấy gói tin đang
được lặp lại với tốc độ 2.257324 giây trong lần kết xuất thứ hai và cuối cùng, bạn thấy gói tin đang
đã nhận lại khách hàng trong lần kết xuất đầu tiên là 2.514648 giây.

Reading đầu ra với Wireshark
Nếu bạn không quen với Wireshark, có một trang web có sẵn để bạn có thể
tải xuống chương trình và tài liệu: http://www.wireshark.org/.

Wireshark là một giao diện người dùng đồ họa có thể được sử dụng để hiển thị các dấu vết này
các tập tin. Nếu bạn có sẵn Wireshark, bạn có thể mở từng tệp theo dõi và hiển thị
nội dung như thể bạn đã nắm bắt các gói bằng cách sử dụng gói sniffer.

XÂY DỰNG CHỦ ĐỀ


Xây dựng a Xe buýt mạng topology
Trong phần này, chúng tôi sẽ mở rộng khả năng làm chủ của chúng tôi về ns-3 thiết bị mạng và các kênh để
bao gồm một ví dụ về mạng lưới xe buýt. ns-3 cung cấp thiết bị mạng và kênh mà chúng tôi gọi là CSMA
(Mang ý nghĩa đa truy cập).

Sản phẩm ns-3 Thiết bị CSMA mô hình hóa một mạng đơn giản theo tinh thần của Ethernet. Một Ethernet thực sự
sử dụng lược đồ CSMA / CD (Đa truy cập theo giác quan sóng mang với tính năng phát hiện va chạm) với
tăng lùi theo cấp số nhân để tranh giành phương tiện truyền tải được chia sẻ. Các ns-3
Các mô hình kênh và thiết bị CSMA chỉ là một tập hợp con của mô hình này.

Cũng giống như chúng ta đã thấy các đối tượng trợ giúp tôpô điểm-điểm khi xây dựng
các cấu trúc liên kết điểm-điểm, chúng ta sẽ thấy các trình trợ giúp cấu trúc liên kết CSMA tương đương trong phần này.
Sự xuất hiện và hoạt động của những trợ giúp này trông khá quen thuộc với bạn.

Chúng tôi cung cấp một tập lệnh mẫu trong thư mục example / tutorial} của chúng tôi. Tập lệnh này được xây dựng dựa trên
các đầu tiên.cc tập lệnh và thêm mạng CSMA vào mô phỏng điểm-điểm mà chúng tôi đã
được xem xét. Hãy tiếp tục và mở ví dụ / hướng dẫn / giây.cc trong trình soạn thảo yêu thích của bạn. Bạn
sẽ thấy đủ rồi ns-3 mã để hiểu hầu hết những gì đang xảy ra trong này
ví dụ, nhưng chúng ta sẽ xem qua toàn bộ tập lệnh và kiểm tra một số kết quả đầu ra.

Cũng như trong đầu tiên.cc ví dụ (và trong tất cả các ví dụ ns-3) tệp bắt đầu bằng emacs
dòng chế độ và một số bản ghi GPL.

Mã thực tế bắt đầu bằng cách tải mô-đun bao gồm các tệp giống như đã được thực hiện trong đầu tiên.cc
thí dụ.

#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3 / csma-module.h"
#include "ns3 / internet-module.h"
#include "ns3 / point-to-point-module.h"
#include "ns3 / apps-module.h"
#include "ns3 / ipv4-global-routing-helper.h"

Một thứ có thể hữu ích một cách đáng ngạc nhiên là một chút nghệ thuật ASCII nhỏ cho thấy phim hoạt hình
của cấu trúc liên kết mạng được xây dựng trong ví dụ. Bạn sẽ tìm thấy một "bản vẽ" tương tự trong
hầu hết các ví dụ của chúng tôi.

Trong trường hợp này, bạn có thể thấy rằng chúng tôi sẽ mở rộng ví dụ từ điểm đến điểm (liên kết
giữa các nút n0 và n1 bên dưới) bằng cách treo một mạng bus ở phía bên phải. Để ý
rằng đây là cấu trúc liên kết mạng mặc định vì bạn thực sự có thể thay đổi số lượng nút
được tạo trên mạng LAN. Nếu bạn đặt nCsma thành một, sẽ có tổng cộng hai nút trên
LAN (kênh CSMA) --- một nút bắt buộc và một nút "phụ". Theo mặc định, có ba
các nút "bổ sung" như được thấy bên dưới:

// Cấu trúc liên kết mạng mặc định
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// điểm-điểm | | | |
// ==================
// LAN 10.1.2.0

Sau đó, không gian tên ns-3 là đã sử dụng và một thành phần ghi nhật ký được xác định. Đây là tất cả chỉ như
nó đã ở trong đó đầu tiên.ccnên vẫn chưa có gì mới.

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

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

Chương trình chính bắt đầu với một chút khác biệt. Chúng tôi sử dụng một cờ dài để
xác định xem có hay không Ứng dụng UdpEchoClientỨng dụng UdpEchoServer khai thác gỗ
các thành phần được kích hoạt. Cờ này mặc định là true (các thành phần ghi nhật ký được bật)
nhưng cho phép chúng tôi tắt ghi nhật ký trong quá trình kiểm tra hồi quy của ví dụ này.

Bạn sẽ thấy một số mã quen thuộc cho phép bạn thay đổi số lượng thiết bị trên
Mạng CSMA thông qua đối số dòng lệnh. Chúng tôi đã làm điều gì đó tương tự khi chúng tôi cho phép
số lượng gói được gửi sẽ được thay đổi trong phần đối số dòng lệnh. Cuối cùng
đảm bảo rằng bạn có ít nhất một nút "phụ".

Mã bao gồm các biến thể của API được đề cập trước đó, vì vậy bạn phải hoàn toàn
cảm thấy thoải mái với đoạn mã sau tại điểm này trong hướng dẫn.

bool dài dòng = true;
uint32_t nCsma = 3;

Dòng lệnh cmd;
cmd.AddValue ("nCsma", "Số lượng \" phụ \ "các nút / thiết bị CSMA", nCsma);
cmd.AddValue ("verbose", "Yêu cầu ứng dụng echo ghi nhật ký nếu đúng", verbose);

cmd.Parse(argc, argv);

nếu (dài dòng)
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

nCsma = nCsma == 0? 1: nCsma;

Bước tiếp theo là tạo hai nút mà chúng ta sẽ kết nối thông qua liên kết điểm-điểm.
Sản phẩm NútContainer được sử dụng để làm điều này giống như đã được thực hiện trong đầu tiên.cc.

NodeContainer p2pNodes;
p2pNodes.Tạo (2);

Tiếp theo, chúng tôi khai báo một NútContainer giữ các nút sẽ là một phần của xe buýt
(CSMA) mạng. Đầu tiên, chúng ta chỉ khởi tạo chính đối tượng vùng chứa.

NodeContainer csmaNodes;
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Tạo (nCsma);

Dòng mã tiếp theo Được nút đầu tiên (như có chỉ mục của một) từ
vùng chứa nút điểm-điểm và thêm nó vào vùng chứa các nút sẽ nhận được CSMA
các thiết bị. Nút được đề cập sẽ kết thúc với một thiết bị điểm-điểm một CSMA
thiết bị. Sau đó, chúng tôi tạo một số nút "bổ sung" tạo nên phần còn lại của CSMA
mạng. Vì chúng ta đã có một nút trong mạng CSMA - nút sẽ có
cả thiết bị mạng điểm-điểm và CSMA, số lượng nút "bổ sung" có nghĩa là số
các nút bạn muốn trong phần CSMA trừ đi một.

Đoạn mã tiếp theo sẽ khá quen thuộc. Chúng tôi khởi tạo một PointToPointTrợ giúp
và đặt giá trị mặc định liên quan Thuộc tính để chúng tôi tạo ra năm megabit mỗi giây
phát trên các thiết bị được tạo bằng trình trợ giúp và độ trễ hai phần nghìn giây trên các kênh
được tạo bởi người trợ giúp.

PointToPointTrợ giúp pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Sau đó, chúng tôi tạo ra một NetThiết BịContainer để theo dõi các thiết bị net point-to-point
và chúng ta đặt thiết bị trên các nút điểm-điểm.

Chúng tôi đã đề cập ở trên rằng bạn sẽ thấy một người trợ giúp cho các thiết bị và kênh CSMA, và
những dòng tiếp theo giới thiệu chúng. Các Trợ giúp Csma hoạt động giống như một PointToPointTrợ giúp, Nhưng
nó tạo và kết nối các thiết bị và kênh CSMA. Trong trường hợp thiết bị CSMA và
cặp kênh, lưu ý rằng tốc độ dữ liệu được chỉ định bởi kênh đặc tính thay vì
thiết bị đặc tính. Điều này là do mạng CSMA thực không cho phép một mạng kết hợp, vì
ví dụ, thiết bị 10Base-T và 100Base-T trên một kênh nhất định. Đầu tiên, chúng tôi đặt tốc độ dữ liệu thành
100 megabit mỗi giây, sau đó đặt độ trễ tốc độ ánh sáng của kênh thành 6560
nano giây (được chọn tùy ý là 1 nano giây trên mỗi foot trên đoạn đường 100 mét).
Lưu ý rằng bạn có thể đặt một đặc tính sử dụng kiểu dữ liệu gốc của nó.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install(csmaNodes);

Cũng giống như chúng tôi đã tạo ra một NetThiết BịContainer để giữ các thiết bị được tạo bởi
PointToPointTrợ giúp chúng tôi tạo ra một NetThiết BịContainer để giữ các thiết bị do chúng tôi tạo ra
Trợ giúp Csma. Chúng tôi gọi là đặt phương pháp của Trợ giúp Csma để cài đặt các thiết bị vào
các nút của csmaNodes NútContainer.

Bây giờ chúng tôi đã tạo các nút, thiết bị và kênh của mình, nhưng chúng tôi không có ngăn xếp giao thức
hiện nay. Cũng như trong đầu tiên.cc script, chúng tôi sẽ sử dụng InternetNgăn XếpTrợ Giúp để cài đặt
những ngăn xếp này.

Ngăn xếp InternetStackHelper;
ngăn xếp.Cài đặt (p2pNodes.Get (0));
ngăn xếp.Cài đặt (csmaNodes);

Nhớ lại rằng chúng tôi đã lấy một trong các nút từ p2pNodes và thêm nó vào
csmaNodes thùng đựng hàng. Vì vậy, chúng tôi chỉ cần cài đặt các ngăn xếp trên phần còn lại p2pNodes
và tất cả các nút trong csmaNodes vùng chứa để che tất cả các nút trong
mô phỏng.

Cũng như trong đầu tiên.cc script ví dụ, chúng tôi sẽ sử dụng Trình trợ giúp địa chỉ Ipv4 đến
gán địa chỉ IP cho các giao diện thiết bị của chúng tôi. Đầu tiên, chúng tôi sử dụng mạng 10.1.1.0 để tạo
hai địa chỉ cần thiết cho hai thiết bị điểm-điểm của chúng tôi.

Địa chỉ Ipv4AddressHelper;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign(p2pDevices);

Nhớ lại rằng chúng tôi lưu các giao diện đã tạo trong một vùng chứa để dễ dàng kéo ra
địa chỉ thông tin sau này để sử dụng trong việc thiết lập các ứng dụng.

Bây giờ chúng ta cần gán địa chỉ IP cho các giao diện thiết bị CSMA của chúng ta. Hoạt động hoạt động
giống như nó đã làm đối với trường hợp điểm-điểm, ngoại trừ bây giờ chúng tôi đang thực hiện thao tác trên
vùng chứa có số lượng thiết bị CSMA thay đổi --- hãy nhớ rằng chúng tôi đã tạo
Thiết bị CSMA có thể thay đổi bằng đối số dòng lệnh. Các thiết bị CSMA sẽ được liên kết
với địa chỉ IP từ số mạng 10.1.2.0 trong trường hợp này, như được thấy bên dưới.

address.SetBase ("10.1.2.0", "255.255.255.0");
Giao diện Ipv4InterfaceContainer csma;
csmaInterfaces = address.Assign (csmaDevices);

Bây giờ chúng ta đã xây dựng một cấu trúc liên kết, nhưng chúng ta cần các ứng dụng. Phần này sẽ
về cơ bản tương tự như phần ứng dụng của đầu tiên.cc nhưng chúng tôi sẽ
khởi tạo máy chủ trên một trong các nút có thiết bị CSMA và máy khách trên
nút chỉ có một thiết bị điểm-điểm.

Đầu tiên, chúng tôi thiết lập máy chủ echo. Chúng tôi tạo ra một UdpEchoMáy ChủTrợ Giúp và cung cấp một yêu cầu bắt buộc
đặc tính giá trị cho hàm tạo là số cổng máy chủ. Nhớ lại rằng cổng này
có thể được thay đổi sau này bằng cách sử dụng Đặt thuộc tính nếu muốn, nhưng chúng tôi yêu cầu nó phải
được cung cấp cho phương thức khởi tạo.

UdpEchoServerTrợ giúp echoServer (9);

ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start (Giây (1.0));
serverApps.Stop (Giây (10.0));

Nhớ lại rằng csmaNodes NútContainer chứa một trong những nút được tạo cho
mạng điểm-điểm và nCsma các nút "phụ". Những gì chúng tôi muốn nhận được là cuối cùng trong số
các nút "phụ". Mục nhập thứ XNUMX của csmaNodes vùng chứa sẽ là điểm-đến-điểm
nút. Sau đó, cách dễ dàng để nghĩ về điều này là nếu chúng ta tạo một nút CSMA "bổ sung", thì nó
sẽ ở chỉ mục một trong những csmaNodes thùng đựng hàng. Bằng cách cảm ứng, nếu chúng ta tạo nCsma "thêm"
nút cuối cùng sẽ ở chỉ mục nCsma. Bạn thấy điều này được trưng bày trong Nhận của người đầu tiên
dòng mã.

Ứng dụng khách được thiết lập chính xác như chúng tôi đã làm trong đầu tiên.cc tập lệnh ví dụ. Lần nữa,
chúng tôi cung cấp yêu cầu Thuộc tính đến UdpEchoClientTrợ giúp trong hàm tạo (trong trường hợp này
địa chỉ từ xa và cổng). Chúng tôi yêu cầu khách hàng gửi các gói đến máy chủ mà chúng tôi chỉ
được cài đặt trên nút CSMA "bổ sung" cuối cùng. Chúng tôi cài đặt ứng dụng khách ở ngoài cùng bên trái
nút điểm-điểm được thấy trong hình minh họa cấu trúc liên kết.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Khoảng thời gian", TimeValue (Giây (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install(p2pNodes.Get(0));
clientApps.Start (Giây (2.0));
clientApps.Stop (Giây (10.0));

Vì chúng tôi đã thực sự xây dựng một kết nối internet ở đây, chúng tôi cần một số hình thức kết nối internet
định tuyến. ns-3 cung cấp cái mà chúng tôi gọi là định tuyến toàn cầu để giúp bạn. Định tuyến toàn cầu mất
lợi thế của thực tế là toàn bộ kết nối internet có thể truy cập được trong mô phỏng và
chạy qua tất cả các nút được tạo cho mô phỏng --- nó thực hiện công việc khó khăn của
thiết lập định tuyến cho bạn mà không cần phải cấu hình bộ định tuyến.

Về cơ bản, điều xảy ra là mỗi nút hoạt động như thể nó là một bộ định tuyến OSPF
giao tiếp ngay lập tức và kỳ diệu với tất cả các bộ định tuyến khác ở hậu trường. Mỗi nút
tạo quảng cáo liên kết và thông báo chúng trực tiếp với người quản lý lộ trình toàn cầu
sử dụng thông tin toàn cục này để xây dựng các bảng định tuyến cho mỗi nút. Cài đặt
lên hình thức định tuyến này là một lớp lót:

Ipv4GlobalRoutingHelper :: PopulateRoutingTables ();

Tiếp theo, chúng tôi bật tính năng theo dõi pcap. Dòng mã đầu tiên cho phép theo dõi pcap trong
người trợ giúp point-to-point bây giờ đã quen thuộc với bạn. Dòng thứ hai cho phép pcap
truy tìm trong trình trợ giúp CSMA và có một tham số bổ sung mà bạn chưa gặp.

pointToPoint.EnablePcapAll ("thứ hai");
csma.EnablePcap ("thứ hai", csmaDevices.Get (1), true);

Mạng CSMA là mạng đa điểm - điểm. Điều này có nghĩa là có thể (và có trong
trường hợp này) nhiều điểm cuối trên một phương tiện được chia sẻ. Mỗi điểm cuối này có một mạng lưới
thiết bị liên kết với nó. Có hai lựa chọn thay thế cơ bản để thu thập dấu vết
thông tin từ một mạng lưới như vậy. Một cách là tạo tệp theo dõi cho mỗi thiết bị mạng
và chỉ lưu trữ các gói được phát ra hoặc tiêu thụ bởi thiết bị mạng đó. Cách khác
là chọn một trong các thiết bị và đặt nó ở chế độ quảng cáo. Thiết bị duy nhất đó sau đó
"đánh hơi" mạng cho tất cả các gói và lưu trữ chúng trong một tệp pcap duy nhất. Đây là cách
tcpdump, ví dụ, hoạt động. Tham số cuối cùng đó cho người trợ giúp CSMA biết có nên hay không
sắp xếp để nắm bắt các gói tin ở chế độ lăng nhăng.

Trong ví dụ này, chúng tôi sẽ chọn một trong các thiết bị trên mạng CSMA và yêu cầu nó
để thực hiện đánh giá lăng nhăng của mạng, do đó mô phỏng những gì tcpdump sẽ làm.
Nếu bạn đang sử dụng máy Linux, bạn có thể làm điều gì đó như tcpdump -i eth0 Để có được
dấu vết. Trong trường hợp này, chúng tôi chỉ định thiết bị sử dụng csmaDevices.Get(1), chọn
thiết bị đầu tiên trong vùng chứa. Đặt thông số cuối cùng thành true sẽ cho phép quảng cáo
chụp.

Phần mã cuối cùng chỉ chạy và xóa mô phỏng giống như đầu tiên.cc
thí dụ.

Trình mô phỏng :: Run ();
Trình mô phỏng :: Phá hủy ();
0 trở về;
}

Để chạy ví dụ này, hãy sao chép thứ hai.cc tập lệnh ví dụ vào thư mục đầu
và sử dụng waf để xây dựng giống như bạn đã làm với đầu tiên.cc thí dụ. Nếu bạn đang ở
thư mục cấp cao nhất của kho lưu trữ mà bạn chỉ cần nhập,

Ví dụ về $ cp / hướng dẫn / second.cc xước / mysecond.cc
$ ./waf

Cảnh báo: Chúng tôi sử dụng tệp thứ hai.cc là một trong những bài kiểm tra hồi quy của chúng tôi để xác minh rằng nó hoạt động
chính xác như chúng tôi nghĩ để làm cho trải nghiệm hướng dẫn của bạn trở nên tích cực.
Điều này có nghĩa là tệp thực thi có tên 2 đã tồn tại trong dự án. Để tránh bất kỳ
nhầm lẫn về những gì bạn đang thực hiện, vui lòng đổi tên thành mysecond.cc đề nghị
ở trên.

Nếu bạn đang làm theo hướng dẫn này một cách tôn giáo (bạn là như vậy, phải không) bạn sẽ vẫn có
bộ biến NS_LOG, vì vậy hãy tiếp tục xóa biến đó và chạy chương trình.

$ export NS_LOG =
$ ./waf --run cào / mysecond

Vì chúng tôi đã thiết lập ứng dụng echo UDP để đăng nhập giống như chúng tôi đã làm trong đầu tiên.cc, bạn sẽ
xem đầu ra tương tự khi bạn chạy tập lệnh.

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.415 giây)
Đã gửi 1024 byte tới 10.1.2.4
Đã nhận 1024 byte từ 10.1.1.1
Đã nhận 1024 byte từ 10.1.2.4

Nhớ lại rằng tin nhắn đầu tiên, "Gửi 1024 byte đến 10.1.2.4, "là ứng dụng khách tiếng vang UDP
gửi một gói đến máy chủ. Trong trường hợp này, máy chủ nằm trên một mạng khác
(10.1.2.0). Tin nhắn thứ hai, "Nhận được 1024 byte từ 10.1.1.1, "là từ tiếng vang UDP
máy chủ, được tạo ra khi nó nhận được gói tiếng vọng. Thông điệp cuối cùng, "Nhận được 1024
byte từ 10.1.2.4, "là từ ứng dụng khách echo, cho biết rằng nó đã nhận được echo của nó
trở lại từ máy chủ.

Nếu bây giờ bạn truy cập và tìm trong thư mục cấp cao nhất, bạn sẽ tìm thấy ba tệp theo dõi:

second-0-0.pcap second-1-0.pcap second-2-0.pcap

Hãy dành một chút thời gian để xem xét cách đặt tên của các tệp này. Tất cả chúng đều có cùng một hình thức,
- - .pcap. Ví dụ: tệp đầu tiên trong danh sách là
thứ hai-0-0.pcap là dấu vết pcap từ nút số không, số không thiết bị. Đây là
thiết bị ròng điểm-điểm trên nút không. Tập tin thứ hai-1-0.pcap là dấu vết pcap cho
thiết bị số không trên nút một, cũng là thiết bị mạng điểm-điểm; và tập tin thứ hai-2-0.pcap is
dấu vết pcap cho thiết bị số không trên nút hai.

Nếu bạn xem lại hình minh họa cấu trúc liên kết ở đầu phần này, bạn sẽ thấy
rằng nút số XNUMX là nút ngoài cùng bên trái của liên kết điểm-điểm và nút một là nút
có cả thiết bị điểm-điểm và thiết bị CSMA. Bạn sẽ thấy rằng nút hai là
nút "bổ sung" đầu tiên trên mạng CSMA và số không thiết bị của nó đã được chọn làm thiết bị
để nắm bắt dấu vết chế độ lăng nhăng.

Bây giờ, chúng ta hãy theo dõi gói echo thông qua internetwork. Đầu tiên, thực hiện một tcpdump của
tệp theo dõi cho nút điểm-điểm ngoài cùng bên trái --- nút không.

$ tcpdump -nn -tt -r thứ hai-0-0.pcap

Bạn sẽ thấy nội dung của tệp pcap được hiển thị:

đọc từ tệp second-0-0.pcap, PPP kiểu liên kết (PPP)
2.000000 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.017607 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Dòng đầu tiên của kết xuất chỉ ra rằng loại liên kết là PPP (điểm-điểm) mà chúng tôi
trông chờ. Sau đó, bạn thấy gói tiếng vọng rời khỏi nút số XNUMX thông qua thiết bị được liên kết với IP
địa chỉ 10.1.1.1 hướng đến địa chỉ IP 10.1.2.4 (nút CSMA ngoài cùng bên phải). Gói này
sẽ di chuyển qua liên kết điểm-điểm và được thiết bị mạng điểm-điểm tiếp nhận trên
nút một. Hãy cùng xem:

$ tcpdump -nn -tt -r thứ hai-1-0.pcap

Bây giờ bạn sẽ thấy đầu ra theo dõi pcap ở phía bên kia của liên kết điểm-điểm:

đọc từ tệp second-1-0.pcap, PPP kiểu liên kết (PPP)
2.003686 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.013921 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Ở đây chúng ta thấy rằng loại liên kết cũng là PPP như chúng ta mong đợi. Bạn thấy gói từ IP
địa chỉ 10.1.1.1 (được gửi lúc 2.000000 giây) hướng đến địa chỉ IP 10.1.2.4
xuất hiện trên giao diện này. Bây giờ, trong nội bộ nút này, gói tin sẽ được chuyển tiếp đến
giao diện CSMA và chúng ta sẽ thấy nó xuất hiện trên thiết bị đó hướng tới
Nơi Đến.

Hãy nhớ rằng chúng tôi đã chọn nút 2 làm nút dò tìm quảng bá cho mạng CSMA vì vậy
sau đó chúng ta hãy nhìn vào thứ hai-2-0.pcap và xem nó có ở đó không.

$ tcpdump -nn -tt -r thứ hai-2-0.pcap

Bây giờ bạn sẽ thấy kết xuất bừa bãi của nút hai, thiết bị số XNUMX:

đọc từ tệp second-2-0.pcap, loại liên kết EN10MB (Ethernet)
2.007698 ARP, Yêu cầu ai-có 10.1.2.4 (ff: ff: ff: ff: ff: ff) cho 10.1.2.1, độ dài 50
2.007710 ARP, Reply 10.1.2.4 is-at 00: 00: 00: 00: 00: 06, độ dài 50
2.007803 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.013815 ARP, Yêu cầu ai-có 10.1.2.1 (ff: ff: ff: ff: ff: ff) cho 10.1.2.4, độ dài 50
2.013828 ARP, Reply 10.1.2.1 is-at 00: 00: 00: 00: 00: 03, độ dài 50
2.013921 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Như bạn có thể thấy, loại liên kết bây giờ là "Ethernet". Tuy nhiên, một cái gì đó mới đã xuất hiện. Các
mạng lưới xe buýt cần ARP, Giao thức phân giải địa chỉ. Node một người biết nó cần gửi
gói đến địa chỉ IP 10.1.2.4, nhưng nó không biết địa chỉ MAC của
nút tương ứng. Nó phát trên mạng CSMA (ff: ff: ff: ff: ff: ff) yêu cầu
thiết bị có địa chỉ IP 10.1.2.4. Trong trường hợp này, nút ngoài cùng bên phải trả lời rằng nó
tại địa chỉ MAC 00: 00: 00: 00: 00: 06. Lưu ý rằng nút hai không liên quan trực tiếp đến việc này
trao đổi, nhưng đang đánh hơi mạng và báo cáo tất cả lưu lượng truy cập mà nó nhìn thấy.

Sự trao đổi này được trình bày trong những dòng sau,

2.007698 ARP, Yêu cầu ai-có 10.1.2.4 (ff: ff: ff: ff: ff: ff) cho 10.1.2.1, độ dài 50
2.007710 ARP, Reply 10.1.2.4 is-at 00: 00: 00: 00: 00: 06, độ dài 50

Sau đó, nút một, thiết bị một tiếp tục và gửi gói tiếng vọng đến máy chủ tiếng vọng UDP tại
Địa chỉ IP 10.1.2.4.

2.007803 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024

Máy chủ nhận được yêu cầu phản hồi và quay lại gói để cố gắng gửi nó trở lại
nguồn. Máy chủ biết rằng địa chỉ này nằm trên một mạng khác mà nó truy cập qua
Địa chỉ IP 10.1.2.1. Điều này là do chúng tôi đã khởi tạo định tuyến toàn cầu và nó đã tìm ra tất cả
của điều này ra cho chúng tôi. Tuy nhiên, nút máy chủ tiếng vọng không biết địa chỉ MAC của nút đầu tiên
Nút CSMA, vì vậy nó phải ARP cho nó giống như nút CSMA đầu tiên phải làm.

2.013815 ARP, Yêu cầu ai-có 10.1.2.1 (ff: ff: ff: ff: ff: ff) cho 10.1.2.4, độ dài 50
2.013828 ARP, Reply 10.1.2.1 is-at 00: 00: 00: 00: 00: 03, độ dài 50

Sau đó, máy chủ sẽ gửi tiếng vọng trở lại nút chuyển tiếp.

2.013921 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Nhìn lại nút ngoài cùng bên phải của liên kết điểm-điểm,

$ tcpdump -nn -tt -r thứ hai-1-0.pcap

Bây giờ bạn có thể thấy gói được lặp lại trở lại liên kết điểm-điểm như là gói cuối cùng
dòng của bãi chứa dấu vết.

đọc từ tệp second-1-0.pcap, PPP kiểu liên kết (PPP)
2.003686 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.013921 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Cuối cùng, bạn có thể nhìn lại nút tạo ra tiếng vang

$ tcpdump -nn -tt -r thứ hai-0-0.pcap

và thấy rằng gói được lặp lại sẽ quay trở lại nguồn sau 2.007602 giây,

đọc từ tệp second-0-0.pcap, PPP kiểu liên kết (PPP)
2.000000 IP 10.1.1.1.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.017607 IP 10.1.2.4.9> 10.1.1.1.49153: UDP, chiều dài 1024

Cuối cùng, hãy nhớ lại rằng chúng tôi đã thêm khả năng kiểm soát số lượng thiết bị CSMA trong
mô phỏng bằng đối số dòng lệnh. Bạn có thể thay đổi đối số này theo cách tương tự như khi
chúng tôi đã xem xét việc thay đổi số lượng gói tin được lặp lại trong đầu tiên.cc thí dụ. Thử chạy
chương trình có số lượng thiết bị "bổ sung" được đặt thành bốn:

$ ./waf --run "xước / mysecond --nCsma = 4"

Bây giờ bạn sẽ thấy,

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.405 giây)
Tại thời điểm khách hàng 2s đã gửi 1024 byte đến 10.1.2.5 cổng 9
Tại thời điểm máy chủ 2.0118s nhận được 1024 byte từ cổng 10.1.1.1 49153
Tại thời điểm máy chủ 2.0118s đã gửi 1024 byte đến cổng 10.1.1.1 49153
Tại thời điểm máy khách 2.02461s nhận được 1024 byte từ cổng 10.1.2.5 cổng 9

Lưu ý rằng máy chủ tiếng vọng hiện đã được chuyển đến vị trí cuối cùng của các nút CSMA, đó là
10.1.2.5 thay vì trường hợp mặc định, 10.1.2.4.

Có thể bạn không hài lòng với tệp theo dõi được tạo bởi người ngoài cuộc trong
mạng CSMA. Bạn có thể thực sự muốn lấy dấu vết từ một thiết bị duy nhất và bạn có thể không
quan tâm đến bất kỳ lưu lượng truy cập nào khác trên mạng. Bạn có thể làm điều này khá dễ dàng.

Hãy xem cào / mysecond.cc và thêm mã đó cho phép chúng tôi
cụ thể. ns-3 trình trợ giúp cung cấp các phương thức lấy số nút và số thiết bị làm
thông số. Hãy tiếp tục và thay thế Kích hoạtPcap cuộc gọi với các cuộc gọi dưới đây.

pointToPoint.EnablePcap ("thứ hai", p2pNodes.Get (0) -> GetId (), 0);
csma.EnablePcap ("thứ hai", csmaNodes.Get (nCsma) -> GetId (), 0, false);
csma.EnablePcap ("thứ hai", csmaNodes.Get (nCsma-1) -> GetId (), 0, false);

Chúng tôi biết rằng chúng tôi muốn tạo một tệp pcap với tên cơ sở là "thứ hai" và chúng tôi cũng biết
rằng thiết bị quan tâm trong cả hai trường hợp sẽ bằng XNUMX, vì vậy những thông số đó không
thật sự thú vị.

Để có được số nút, bạn có hai lựa chọn: thứ nhất, các nút được đánh số trong
thời trang tăng đơn điệu bắt đầu từ XNUMX theo thứ tự bạn đã tạo
họ. Một cách để có được số nút là tìm ra số này "theo cách thủ công" bằng cách
dự tính thứ tự tạo nút. Nếu bạn nhìn vào cấu trúc liên kết mạng
hình minh họa ở đầu tệp, chúng tôi đã làm điều này cho bạn và bạn có thể thấy rằng
nút CSMA cuối cùng sẽ là số nút nCsma + 1. Cách tiếp cận này có thể trở nên khó chịu
khó trong các mô phỏng lớn hơn.

Một cách thay thế mà chúng tôi sử dụng ở đây là nhận ra rằng NútContainer chứa
trỏ tới ns-3 Node Các đối tượng. Các Node Đối tượng có một phương thức được gọi là NhậnId cái nào sẽ
trả về ID của nút đó, là số nút mà chúng tôi tìm kiếm. Chúng ta hãy đi xem xét
Doxygen cho Node và định vị phương pháp đó, phương pháp này nằm sâu hơn trong ns-3 mã lõi
hơn chúng ta đã thấy cho đến nay; nhưng đôi khi bạn phải siêng năng tìm kiếm những thứ hữu ích.

Đi tới tài liệu Doxygen cho bản phát hành của bạn (nhớ lại rằng bạn có thể tìm thấy nó trên
trang web của dự án). Bạn có thể đến Node tài liệu bằng cách xem qua
Tab "Lớp học" và cuộn xuống "Danh sách lớp học" cho đến khi bạn tìm thấy ns3 :: Node. Chọn
ns3 :: Node và bạn sẽ được đưa đến tài liệu cho Node lớp học. Nếu bạn bây giờ
cuộn xuống NhậnId và chọn nó, bạn sẽ được đưa đến chi tiết
tài liệu cho phương pháp. Sử dụng NhậnId phương pháp có thể xác định số nút
dễ dàng hơn nhiều trong các cấu trúc liên kết phức tạp.

Hãy xóa các tệp theo dõi cũ ra khỏi thư mục cấp cao nhất để tránh nhầm lẫn về
chuyện gì đang xảy ra,

$ rm * .pcap
$ rm * .tr

Nếu bạn xây dựng tập lệnh mới và chạy cài đặt mô phỏng nCsma để 100,

$ ./waf --run "xước / mysecond --nCsma = 100"

bạn sẽ thấy kết quả sau:

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.407 giây)
Tại thời điểm khách hàng 2s đã gửi 1024 byte đến 10.1.2.101 cổng 9
Tại thời điểm máy chủ 2.0068s nhận được 1024 byte từ cổng 10.1.1.1 49153
Tại thời điểm máy chủ 2.0068s đã gửi 1024 byte đến cổng 10.1.1.1 49153
Tại thời điểm máy khách 2.01761s nhận được 1024 byte từ cổng 10.1.2.101 cổng 9

Lưu ý rằng máy chủ tiếng vọng hiện được đặt ở 10.1.2.101, tương ứng với có 100
các nút CSMA "bổ sung" với máy chủ tiếng vọng trên nút cuối cùng. Nếu bạn liệt kê các tệp pcap trong
thư mục cấp cao nhất mà bạn sẽ thấy,

second-0-0.pcap second-100-0.pcap second-101-0.pcap

Tệp theo dõi thứ hai-0-0.pcap là thiết bị điểm-điểm "ngoài cùng bên trái" là thiết bị tạo tiếng vang
nguồn gói tin. Tập tin thứ hai-101-0.pcap tương ứng với thiết bị CSMA ngoài cùng bên phải
là nơi máy chủ tiếng vọng cư trú. Bạn có thể nhận thấy rằng tham số cuối cùng trên
lệnh gọi để kích hoạt theo dõi pcap trên nút máy chủ tiếng vọng là sai. Điều này có nghĩa là dấu vết
được tập hợp trên nút đó ở chế độ không quảng cáo.

Để minh họa sự khác biệt giữa dấu vết lăng nhăng và không lăng nhăng, chúng tôi cũng
đã yêu cầu một dấu vết không bừa bãi cho nút tiếp theo đến nút cuối cùng. Hãy tiếp tục và xem xét
các tcpdump cho thứ hai-100-0.pcap.

$ tcpdump -nn -tt -r thứ hai-100-0.pcap

Bây giờ bạn có thể thấy rằng nút 100 thực sự là một người ngoài cuộc trong trao đổi tiếng vọng. Duy nhất
các gói mà nó nhận được là các yêu cầu ARP được phát tới toàn bộ CSMA
mạng lưới.

đọc từ tệp second-100-0.pcap, loại liên kết EN10MB (Ethernet)
2.006698 ARP, Yêu cầu ai-có 10.1.2.101 (ff: ff: ff: ff: ff: ff) cho 10.1.2.1, độ dài 50
2.013815 ARP, Yêu cầu ai-có 10.1.2.1 (ff: ff: ff: ff: ff: ff) cho 10.1.2.101, độ dài 50

Bây giờ hãy nhìn vào tcpdump cho thứ hai-101-0.pcap.

$ tcpdump -nn -tt -r thứ hai-101-0.pcap

Bây giờ bạn có thể thấy rằng nút 101 thực sự là người tham gia vào quá trình trao đổi tiếng vọng.

đọc từ tệp second-101-0.pcap, loại liên kết EN10MB (Ethernet)
2.006698 ARP, Yêu cầu ai-có 10.1.2.101 (ff: ff: ff: ff: ff: ff) cho 10.1.2.1, độ dài 50
2.006698 ARP, Reply 10.1.2.101 is-at 00: 00: 00: 00: 00: 67, độ dài 50
2.006803 IP 10.1.1.1.49153> 10.1.2.101.9: UDP, chiều dài 1024
2.013803 ARP, Yêu cầu ai-có 10.1.2.1 (ff: ff: ff: ff: ff: ff) cho 10.1.2.101, độ dài 50
2.013828 ARP, Reply 10.1.2.1 is-at 00: 00: 00: 00: 00: 03, độ dài 50
2.013828 IP 10.1.2.101.9> 10.1.1.1.49153: UDP, chiều dài 1024

Mô hình, Thuộc tính Reality
Đây là một nơi thuận tiện để thực hiện một chuyến du ngoạn nhỏ và tạo nên một điểm quan trọng. Nó có thể
hoặc có thể không rõ ràng đối với bạn, nhưng bất cứ khi nào người ta sử dụng một mô phỏng, điều quan trọng là phải
hiểu chính xác những gì đang được mô hình hóa và những gì không. Ví dụ, nó rất hấp dẫn để
hãy nghĩ về các thiết bị và kênh CSMA được sử dụng trong phần trước như thể chúng có thật
Thiết bị Ethernet; và mong đợi một kết quả mô phỏng phản ánh trực tiếp những gì sẽ xảy ra
trong một Ethernet thực. Đây không phải là trường hợp.

Theo định nghĩa, một mô hình là một sự trừu tượng của thực tế. Cuối cùng là trách nhiệm
của tác giả kịch bản mô phỏng để xác định cái gọi là "phạm vi độ chính xác" và "miền
khả năng ứng dụng "của mô phỏng nói chung, và do đó là các bộ phận cấu thành của nó.

Trong một số trường hợp, như csma, có thể khá dễ dàng để xác định đâu là không được mô hình hóa. Qua
đọc mô tả mô hình (csma.h) bạn có thể thấy rằng không có phát hiện va chạm
trong mô hình CSMA và quyết định xem việc sử dụng nó sẽ áp dụng như thế nào trong mô phỏng của bạn hoặc
cảnh báo bạn có thể muốn đưa vào kết quả của mình. Trong các trường hợp khác, nó có thể khá dễ dàng
để định cấu hình các hành vi có thể không phù hợp với bất kỳ thực tế nào mà bạn có thể ra ngoài và mua. Nó
sẽ chứng minh đáng giá khi dành thời gian điều tra một vài trường hợp như vậy và làm thế nào
bạn có thể dễ dàng đi ra ngoài giới hạn của thực tế trong mô phỏng của mình.

Như bạn đã thấy, ns-3 cung cấp Thuộc tính mà người dùng có thể dễ dàng đặt để thay đổi mô hình
hành vi. Hãy xem xét hai trong số Thuộc tính của Thiết bị CsmaNet: Núi
Chế độ đóng gói. Các Núi thuộc tính chỉ ra Đơn vị truyền tối đa đến
thiết bị. Đây là kích thước của Đơn vị dữ liệu giao thức (PDU) lớn nhất mà thiết bị có thể
gửi.

MTU mặc định là 1500 byte trong Thiết bị CsmaNet. Mặc định này tương ứng với một số
tìm thấy trong RFC 894, "Một tiêu chuẩn để truyền biểu đồ IP qua Ethernet
Mạng. "Con số thực sự được tính từ kích thước gói tối đa cho 10Base5
mạng (đầy đủ thông số kỹ thuật Ethernet) - 1518 byte. Nếu bạn trừ đi đóng gói DIX
chi phí chung cho các gói Ethernet (18 byte), bạn sẽ nhận được kích thước dữ liệu tối đa có thể
(MTU) 1500 byte. Người ta cũng có thể thấy rằng MTU đối với mạng IEEE 802.3 là 1492
byte. Điều này là do việc đóng gói LLC / SNAP bổ sung thêm XNUMX byte chi phí vào
cái túi. Trong cả hai trường hợp, phần cứng bên dưới chỉ có thể gửi 1518 byte, nhưng dữ liệu
kích thước là khác nhau.

Để đặt chế độ đóng gói, Thiết bị CsmaNet cung cấp một đặc tính gọi là
Chế độ đóng gói mà có thể nhận các giá trị mười or LLC. Chúng tương ứng với Ethernet
và đóng khung LLC / SNAP tương ứng.

Nếu một người rời khỏi Núi ở 1500 byte và thay đổi chế độ đóng gói thành LLC, kết quả
sẽ là một mạng đóng gói các PDU 1500 byte với khung LLC / SNAP dẫn đến
các gói có kích thước 1526 byte, sẽ là bất hợp pháp trong nhiều mạng, vì chúng có thể truyền
tối đa là 1518 byte cho mỗi gói. Điều này rất có thể sẽ dẫn đến một mô phỏng
khá tinh vi không phản ánh thực tế mà bạn có thể mong đợi.

Chỉ để làm phức tạp hình ảnh, tồn tại các khung hình jumbo (1500 <MTU <= 9000 byte) và
khung siêu jumbo (MTU> 9000 byte) không bị IEEE chính thức xử phạt nhưng được
khả dụng trong một số mạng tốc độ cao (Gigabit) và NIC. Người ta có thể rời khỏi
chế độ đóng gói được đặt thành mườivà đặt Núi đặc tính trên Thiết bị CsmaNet đến 64000 byte
- mặc dù một liên kết CsmaKênh Tốc độ dữ liệu được đặt ở 10 megabit / giây. Điều này
về cơ bản sẽ mô hình hóa một bộ chuyển mạch Ethernet được làm từ 1980Base10 theo phong cách ma cà rồng những năm 5
mạng hỗ trợ các biểu đồ dữ liệu siêu jumbo. Đây chắc chắn không phải là thứ đã
đã từng được sản xuất, cũng như không bao giờ được sản xuất, nhưng nó khá dễ dàng để bạn định cấu hình.

Trong ví dụ trước, bạn đã sử dụng dòng lệnh để tạo mô phỏng có 100
csma điểm giao. Bạn có thể dễ dàng tạo một mô phỏng với 500 nút. nếu bạn
thực sự đang mô hình hóa mạng vòi ma cà rồng 10Base5 đó, độ dài tối đa của một thông số kỹ thuật đầy đủ
Cáp Ethernet dài 500 mét, với khoảng cách chạm tối thiểu là 2.5 mét. Điều đó có nghĩa là ở đó
chỉ có thể là 200 lần nhấn trên một mạng thực. Bạn có thể dễ dàng xây dựng một công trình bất hợp pháp
mạng theo cách đó. Điều này có thể dẫn đến một mô phỏng có ý nghĩa hoặc không
tùy thuộc vào những gì bạn đang cố gắng tạo mô hình.

Các tình huống tương tự có thể xảy ra ở nhiều nơi trong ns-3 và trong bất kỳ trình mô phỏng nào. Ví dụ,
bạn có thể định vị các nút theo cách mà chúng chiếm cùng một không gian tại
đồng thời, hoặc bạn có thể định cấu hình bộ khuếch đại hoặc mức độ tiếng ồn vi phạm
các định luật vật lý cơ bản.

ns-3 nói chung ưa thích sự linh hoạt và nhiều mô hình sẽ cho phép thiết lập tự do Thuộc tính
mà không cố gắng thực thi bất kỳ tính nhất quán tùy ý hoặc thông số kỹ thuật cơ bản cụ thể nào.

Điều cần mang về nhà từ đây là ns-3 sẽ cung cấp một cơ sở siêu linh hoạt
để bạn thử nghiệm. Bạn phải hiểu những gì bạn đang yêu cầu hệ thống
để làm và để đảm bảo rằng các mô phỏng bạn tạo có một số ý nghĩa và một số
kết nối với một thực tế do bạn xác định.

Xây dựng a Không dây mạng topology
Trong phần này, chúng tôi sẽ mở rộng hơn nữa kiến ​​thức của chúng tôi về ns-3 thiết bị mạng và
các kênh để trình bày một ví dụ về mạng không dây. ns-3 cung cấp một tập hợp các mô hình 802.11
nỗ lực cung cấp triển khai cấp MAC chính xác của thông số kỹ thuật 802.11
và mô hình cấp PHY "không chậm" của đặc điểm kỹ thuật 802.11a.

Cũng giống như chúng ta đã thấy các đối tượng trợ giúp tô pô CSMA và point-to-point khi
xây dựng các cấu trúc liên kết điểm-điểm, chúng ta sẽ thấy tương đương wifi topo trợ giúp trong
phần này. Sự xuất hiện và hoạt động của những trợ giúp này trông khá quen thuộc với
bạn.

Chúng tôi cung cấp một tập lệnh mẫu trong ví dụ / hướng dẫn danh mục. Tập lệnh này được xây dựng dựa trên
các thứ hai.cc script và thêm mạng Wifi. Hãy tiếp tục và mở
ví dụ / hướng dẫn / thứ ba.cc trong trình soạn thảo yêu thích của bạn. Bạn sẽ thấy đủ rồi
ns-3 mã để hiểu hầu hết những gì đang diễn ra trong ví dụ này, nhưng có một số
mọi thứ, vì vậy chúng ta sẽ xem qua toàn bộ tập lệnh và kiểm tra một số kết quả đầu ra.

Cũng như trong thứ hai.cc ví dụ (và trong tất cả ns-3 ví dụ) tệp bắt đầu bằng emacs
dòng chế độ và một số bản ghi GPL.

Hãy xem nghệ thuật ASCII (được tái tạo bên dưới) hiển thị cấu trúc liên kết mạng mặc định
được xây dựng trong ví dụ. Bạn có thể thấy rằng chúng tôi sẽ mở rộng thêm ví dụ của chúng tôi
bằng cách treo mạng không dây ở bên trái. Lưu ý rằng đây là mạng mặc định
cấu trúc liên kết vì bạn thực sự có thể thay đổi số lượng nút được tạo trên mạng có dây và không dây
mạng lưới. Cũng như trong thứ hai.cc trường hợp kịch bản, nếu bạn thay đổi nCsma, nó sẽ cung cấp cho bạn một
số lượng nút CSMA "bổ sung". Tương tự, bạn có thể đặt nWifi để kiểm soát bao nhiêu STA
(trạm) các nút được tạo trong mô phỏng. Sẽ luôn có một AP (điểm truy cập)
trên mạng không dây. Theo mặc định, có ba nút CSMA "bổ sung" và ba
không dây STA điểm giao.

Mã bắt đầu bằng cách tải mô-đun bao gồm các tệp giống như đã được thực hiện trong thứ hai.cc thí dụ.
Có một số tính năng mới bao gồm tương ứng với mô-đun Wifi và tính di động
mô-đun mà chúng ta sẽ thảo luận bên dưới.

#include "ns3 / core-module.h"
#include "ns3 / point-to-point-module.h"
#include "ns3 / network-module.h"
#include "ns3 / apps-module.h"
#include "ns3 / wifi-module.h"
#include "ns3 / Mobile-module.h"
#include "ns3 / csma-module.h"
#include "ns3 / internet-module.h"

Hình minh họa cấu trúc liên kết mạng như sau:

// Cấu trúc liên kết mạng mặc định
//
// Wi-Fi 10.1.3.0
// ÁP
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// điểm-điểm | | | |
// ==================
// LAN 10.1.2.0

Bạn có thể thấy rằng chúng tôi đang thêm một thiết bị mạng mới vào nút ở phía bên trái của
liên kết điểm-điểm trở thành điểm truy cập cho mạng không dây. Một số
Các nút STA không dây được tạo để điền vào mạng 10.1.3.0 mới như hình bên trái
bên của hình minh họa.

Sau hình minh họa, ns-3 không gian tên là đã sử dụng và một thành phần ghi nhật ký được xác định.
Điều này chắc hẳn đã khá quen thuộc vào thời điểm hiện tại.

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

NS_LOG_COMPONENT_DEFINE ("Ví dụ về ThirdScript");

Chương trình chính bắt đầu giống như thứ hai.cc bằng cách thêm một số tham số dòng lệnh cho
bật hoặc tắt các thành phần ghi nhật ký và để thay đổi số lượng thiết bị được tạo.

bool dài dòng = true;
uint32_t nCsma = 3;
uint32_t nWifi = 3;

Dòng lệnh cmd;
cmd.AddValue ("nCsma", "Số lượng \" phụ \ "các nút / thiết bị CSMA", nCsma);
cmd.AddValue ("nWifi", "Số lượng thiết bị wifi STA", nWifi);
cmd.AddValue ("verbose", "Yêu cầu ứng dụng echo ghi nhật ký nếu đúng", verbose);

cmd.Parse (argc, argv);

nếu (dài dòng)
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

Cũng giống như trong tất cả các ví dụ trước, bước tiếp theo là tạo hai nút mà chúng ta sẽ
kết nối thông qua liên kết điểm-điểm.

NodeContainer p2pNodes;
p2pNodes.Tạo (2);

Tiếp theo, chúng ta gặp lại một người bạn cũ. Chúng tôi khởi tạo một PointToPointTrợ giúp và đặt liên kết
mặc định Thuộc tính để chúng tôi tạo bộ phát XNUMX megabit mỗi giây trên các thiết bị
được tạo bằng trình trợ giúp và độ trễ hai mili giây trên các kênh do trình trợ giúp tạo.
Chúng tôi sau đó cài đặt các thiết bị trên các nút và kênh giữa chúng.

PointToPointTrợ giúp pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Tiếp theo, chúng tôi khai báo một NútContainer giữ các nút sẽ là một phần của xe buýt
(CSMA) mạng.

NodeContainer csmaNodes;
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Tạo (nCsma);

Dòng mã tiếp theo Được nút đầu tiên (như có chỉ mục của một) từ
vùng chứa nút điểm-điểm và thêm nó vào vùng chứa các nút sẽ nhận được CSMA
các thiết bị. Nút được đề cập sẽ kết thúc với thiết bị điểm-điểm và CSMA
thiết bị. Sau đó, chúng tôi tạo một số nút "bổ sung" tạo nên phần còn lại của CSMA
mạng lưới.

Sau đó, chúng tôi tạo ra một Trợ giúp Csma và đặt nó Thuộc tính như chúng ta đã làm trong ví dụ trước.
Chúng tôi tạo ra một NetThiết BịContainer để theo dõi các thiết bị mạng CSMA đã tạo và sau đó chúng tôi
đặt Thiết bị CSMA trên các nút đã chọn.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install(csmaNodes);

Tiếp theo, chúng ta sẽ tạo các nút sẽ là một phần của mạng Wifi. Chúng tôi là
sẽ tạo một số nút "trạm" như được chỉ định bởi đối số dòng lệnh và
chúng tôi sẽ sử dụng nút "ngoài cùng bên trái" của liên kết điểm-điểm làm nút cho
điểm truy cập.

NodeContainer wifiStaNodes;
wifiStaNodes.Tạo (nWifi);
NodeContainer wifiApNode = p2pNodes.Get(0);

Đoạn mã tiếp theo xây dựng các thiết bị wifi và kênh kết nối giữa
các nút wifi này. Đầu tiên, chúng tôi định cấu hình PHY và trình trợ giúp kênh:

Kênh YansWifiChannelHelper = YansWifiChannelHelper :: Mặc định ();
YansWifiPhyHelper phy = YansWifiPhyHelper :: Default ();

Để đơn giản, mã này sử dụng cấu hình lớp PHY mặc định và các mô hình kênh
được ghi lại trong tài liệu API doxygen cho
YansWifiChannelHelper :: Mặc địnhYansWifiPhyHelper :: Mặc định các phương pháp. Một khi các đối tượng này
được tạo, chúng tôi tạo một đối tượng kênh và liên kết nó với trình quản lý đối tượng lớp PHY của chúng tôi
để đảm bảo rằng tất cả các đối tượng lớp PHY được tạo bởi YansWifiPhyTrợ giúp chia sẻ
cùng một kênh cơ bản, tức là chúng chia sẻ cùng một phương tiện không dây và có thể
giao tiếp và can thiệp:

phy.SetChannel(channel.Create());

Sau khi trình trợ giúp PHY được định cấu hình, chúng ta có thể tập trung vào lớp MAC. Ở đây chúng tôi chọn làm việc
với MAC không phải Qos, vì vậy chúng tôi sử dụng đối tượng NqosWifiMacHelper để thiết lập các tham số MAC.

WifiHelper wifi = WifiHelper :: Default ();
wifi.SetRemoteStationManager ("ns3 :: AarfWifiManager");

NqosWifiMacHelper mac = NqosWifiMacHelper :: Default ();

Sản phẩm SetRemoteStationManager phương pháp cho người trợ giúp biết loại thuật toán kiểm soát tốc độ để
sử dụng. Ở đây, nó đang yêu cầu người trợ giúp sử dụng thuật toán AARF --- tất nhiên, chi tiết là
có sẵn trong Doxygen.

Tiếp theo, chúng tôi định cấu hình loại MAC, SSID của mạng cơ sở hạ tầng mà chúng tôi muốn
thiết lập và đảm bảo rằng các trạm của chúng tôi không thực hiện thăm dò đang hoạt động:

Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3 :: StaWifiMac",
"Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (false));

Đầu tiên, mã này tạo một đối tượng nhận dạng bộ dịch vụ (SSID) 802.11 sẽ được sử dụng
để đặt giá trị của "Ssid" đặc tính của việc triển khai lớp MAC. Thứ cụ thể
loại lớp MAC sẽ được tạo bởi trình trợ giúp được chỉ định bởi đặc tính như là của
loại "ns3 :: StaWifiMac". Việc sử dụng NqosWifiMacTrợ giúp sẽ đảm bảo rằng
"QosSupported" đặc tính đối với các đối tượng MAC đã tạo được đặt là false. Sự kết hợp của những
hai cấu hình có nghĩa là phiên bản MAC được tạo tiếp theo sẽ là phiên bản không phải của QoS không phải AP
trạm (STA) trong một BSS cơ sở hạ tầng (tức là BSS với một AP). cuối cùng
"ActiveProbing" đặc tính được đặt thành false. Điều này có nghĩa là các yêu cầu thăm dò sẽ không
được gửi bởi MAC do người trợ giúp này tạo.

Khi tất cả các thông số dành riêng cho trạm được cấu hình đầy đủ, cả ở MAC và PHY
các lớp, chúng ta có thể gọi đặt phương pháp để tạo các thiết bị wifi trong số này
các trạm:

NetDeviceContainer staDevices;
staDevices = wifi.Install(phy, mac, wifiStaNodes);

Chúng tôi đã định cấu hình Wi-Fi cho tất cả các nút STA của mình và bây giờ chúng tôi cần định cấu hình AP
(điểm truy cập). Chúng tôi bắt đầu quá trình này bằng cách thay đổi giá trị mặc định Thuộc tính của
NqosWifiMacTrợ giúp để phản ánh các yêu cầu của AP.

mac.SetType ("ns3 :: ApWifiMac",
"Ssid", SsidValue (ssid));

Trong trường hợp này, NqosWifiMacTrợ giúp sẽ tạo các lớp MAC của "ns3 :: ApWifiMac",
phần sau chỉ định rằng một cá thể MAC được định cấu hình làm AP sẽ được tạo, với
loại trợ giúp ngụ ý rằng "QosSupported" đặc tính nên được đặt thành false - vô hiệu hóa
Hỗ trợ QoS kiểu 802.11e / WMM tại các AP đã tạo.

Các dòng tiếp theo tạo một AP duy nhất chia sẻ cùng một nhóm cấp PHY Thuộc tính (Và
kênh) như các đài:

NetDeviceContainer apDevices;
apDevices = wifi.Install(phy, mac, wifiApNode);

Bây giờ, chúng tôi sẽ thêm các mô hình di động. Chúng tôi muốn các nút STA phải di động, lang thang
xung quanh bên trong một hộp giới hạn và chúng tôi muốn làm cho nút AP đứng yên. Chúng tôi sử dụng
Trợ giúp di động để làm cho điều này dễ dàng cho chúng tôi. Đầu tiên, chúng tôi khởi tạo một Trợ giúp di động vật
và đặt một số Thuộc tính kiểm soát chức năng "trình phân bổ vị trí".

Khả năng di chuyển tốt hơn;

Mobile.SetPositionAllocator ("ns3 :: GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));

Mã này yêu cầu người trợ giúp di động sử dụng lưới hai chiều để đặt
Các nút STA. Hãy tự do khám phá Doxygen cho lớp học ns3 :: GridPositionAllocator để xem
chính xác những gì đang được thực hiện.

Chúng tôi đã sắp xếp các nút của mình trên một lưới ban đầu, nhưng bây giờ chúng tôi cần cho chúng biết cách di chuyển.
Chúng tôi chọn RandomWalk2dMobilityMô hình trong đó có các nút di chuyển theo một hướng ngẫu nhiên tại
một tốc độ ngẫu nhiên xung quanh bên trong một hộp giới hạn.

Mobile.SetMobilityModel ("ns3 :: RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Hình chữ nhật (-50, 50, -50, 50)));

Bây giờ chúng tôi nói với Trợ giúp di động để cài đặt các mô hình di động trên các nút STA.

Mobile.Install (wifiStaNodes);

Chúng tôi muốn điểm truy cập vẫn ở một vị trí cố định trong quá trình mô phỏng. chúng tôi
thực hiện điều này bằng cách thiết lập mô hình di động cho nút này là
ns3 :: ConstantPositionMobilityModel:

di động.SetMobilityModel ("ns3 :: ConstantPositionMobilityModel");
Mobile.Install (wifiApNode);

Giờ đây, chúng tôi đã tạo các nút, thiết bị và kênh của mình cũng như các mô hình di động được chọn cho
Các nút Wi-Fi, nhưng chúng tôi không có ngăn xếp giao thức nào. Cũng như chúng tôi đã làm trước đây nhiều
lần, chúng tôi sẽ sử dụng InternetNgăn XếpTrợ Giúp để cài đặt các ngăn xếp này.

Ngăn xếp InternetStackHelper;
ngăn xếp.Cài đặt (csmaNodes);
ngăn xếp.Cài đặt (wifiApNode);
ngăn xếp.Cài đặt (wifiStaNodes);

Cũng như trong thứ hai.cc script ví dụ, chúng tôi sẽ sử dụng Trình trợ giúp địa chỉ Ipv4 đến
gán địa chỉ IP cho các giao diện thiết bị của chúng tôi. Đầu tiên, chúng tôi sử dụng mạng 10.1.1.0 để tạo
hai địa chỉ cần thiết cho hai thiết bị điểm-điểm của chúng tôi. Sau đó, chúng tôi sử dụng mạng 10.1.2.0
để gán địa chỉ cho mạng CSMA và sau đó chúng tôi gán địa chỉ từ mạng 10.1.3.0
cho cả thiết bị STA và AP trên mạng không dây.

Địa chỉ Ipv4AddressHelper;

address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign(p2pDevices);

address.SetBase ("10.1.2.0", "255.255.255.0");
Giao diện Ipv4InterfaceContainer csma;
csmaInterfaces = address.Assign (csmaDevices);

address.SetBase ("10.1.3.0", "255.255.255.0");
địa chỉ.Assign (staDevices);
địa chỉ.Assign (apDevices);

Chúng tôi đặt máy chủ echo ở nút "ngoài cùng bên phải" trong hình minh họa ở đầu
tập tin. Chúng tôi đã làm điều này trước đây.

UdpEchoServerTrợ giúp echoServer (9);

ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start (Giây (1.0));
serverApps.Stop (Giây (10.0));

Và chúng tôi đặt ứng dụng khách echo trên nút STA cuối cùng mà chúng tôi đã tạo, trỏ nó đến máy chủ trên
mạng CSMA. Chúng tôi cũng đã từng thấy các hoạt động tương tự trước đây.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Khoảng thời gian", TimeValue (Giây (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps =
echoClient.Install(wifiStaNodes.Get(nWifi - 1));
clientApps.Start (Giây (2.0));
clientApps.Stop (Giây (10.0));

Vì chúng tôi đã xây dựng kết nối internet ở đây, chúng tôi cần bật định tuyến kết nối internet giống như
chúng tôi đã làm trong thứ hai.cc tập lệnh ví dụ.

Ipv4GlobalRoutingHelper :: PopulateRoutingTables ();

Một điều có thể khiến một số người dùng ngạc nhiên là thực tế là mô phỏng chúng tôi vừa tạo
sẽ không bao giờ "tự nhiên" dừng lại. Điều này là do chúng tôi đã yêu cầu điểm truy cập không dây
tạo báo hiệu. Nó sẽ tạo ra các báo hiệu mãi mãi và điều này sẽ dẫn đến trình mô phỏng
các sự kiện đang được lên lịch trong tương lai vô thời hạn, vì vậy chúng tôi phải yêu cầu trình mô phỏng dừng lại
mặc dù nó có thể có các sự kiện tạo đèn hiệu được lên lịch. Dòng mã sau
yêu cầu trình mô phỏng dừng lại để chúng tôi không mô phỏng đèn hiệu mãi mãi và nhập những gì
thực chất là một vòng lặp vô tận.

Trình mô phỏng :: Dừng (Giây (10.0));

Chúng tôi tạo ra chỉ số theo dõi đủ để bao gồm cả ba mạng:

pointToPoint.EnablePcapAll ("thứ ba");
phy.EnablePcap ("thứ ba", apDevices.Get (0));
csma.EnablePcap ("thứ ba", csmaDevices.Get (0), true);

Ba dòng mã này sẽ bắt đầu theo dõi pcap trên cả hai nút điểm-điểm
đóng vai trò là xương sống của chúng tôi, sẽ bắt đầu theo dõi chế độ (theo dõi) lăng nhăng trên mạng Wifi,
và sẽ bắt đầu một dấu vết lăng nhăng trên mạng CSMA. Điều này sẽ cho chúng ta thấy tất cả
lưu lượng truy cập với số lượng tệp theo dõi tối thiểu.

Cuối cùng, chúng tôi thực sự chạy mô phỏng, dọn dẹp và sau đó thoát khỏi chương trình.

Trình mô phỏng :: Run ();
Trình mô phỏng :: Phá hủy ();
0 trở về;
}

Để chạy ví dụ này, bạn phải sao chép thứ ba.cc tập lệnh ví dụ vào
thư mục đầu và sử dụng Waf để xây dựng giống như bạn đã làm với thứ hai.cc thí dụ. nếu bạn
nằm trong thư mục cấp cao nhất của kho lưu trữ mà bạn sẽ nhập,

Ví dụ về $ cp / hướng dẫn / third.cc xước / mythird.cc
$ ./waf
$ ./waf --run cào / mythird

Một lần nữa, vì chúng tôi đã thiết lập các ứng dụng echo UDP giống như chúng tôi đã làm trong thứ hai.cc
script, bạn sẽ thấy đầu ra tương tự.

Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.407 giây)
Tại thời điểm khách hàng 2s đã gửi 1024 byte đến 10.1.2.4 cổng 9
Tại thời điểm máy chủ 2.01796s nhận được 1024 byte từ cổng 10.1.3.3 49153
Tại thời điểm máy chủ 2.01796s đã gửi 1024 byte đến cổng 10.1.3.3 49153
Tại thời điểm máy khách 2.03364s nhận được 1024 byte từ cổng 10.1.2.4 cổng 9

Nhớ lại rằng tin nhắn đầu tiên, Gửi 1024 byte đến 10.1.2.4, "là ứng dụng khách tiếng vang UDP
gửi một gói đến máy chủ. Trong trường hợp này, máy khách đang sử dụng mạng không dây
(10.1.3.0). Tin nhắn thứ hai, "Nhận được 1024 byte từ 10.1.3.3, "là từ tiếng vang UDP
máy chủ, được tạo ra khi nó nhận được gói tiếng vọng. Thông điệp cuối cùng, "Nhận được 1024
byte từ 10.1.2.4, "là từ ứng dụng khách echo, cho biết rằng nó đã nhận được echo của nó
trở lại từ máy chủ.

Nếu bây giờ bạn truy cập và tìm trong thư mục cấp cao nhất, bạn sẽ tìm thấy bốn tệp theo dõi từ
mô phỏng này, hai từ nút không và hai từ nút một:

third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap

Tệp "third-0-0.pcap" tương ứng với thiết bị điểm-điểm trên nút số XNUMX -
mặt trái của "xương sống". Tệp "third-1-0.pcap" tương ứng với điểm đến điểm
thiết bị trên nút một - phía bên phải của "xương sống". Tệp "third-0-1.pcap" sẽ là
dấu vết (chế độ giám sát) bừa bãi từ mạng Wifi và tệp "third-1-1.pcap"
sẽ là dấu vết lăng nhăng từ mạng CSMA. Bạn có thể xác minh điều này bằng cách kiểm tra
mật mã?

Vì ứng dụng khách echo nằm trên mạng Wifi, chúng ta hãy bắt đầu ở đó. Chúng ta hãy nhìn vào
dấu vết lăng nhăng (chế độ giám sát) mà chúng tôi đã chụp được trên mạng đó.

$ tcpdump -nn -tt -r thứ ba-0-1.pcap

Bạn sẽ thấy một số nội dung trông có vẻ như wifi mà bạn chưa từng thấy ở đây:

đọc từ tệp third-0-1.pcap, loại liên kết IEEE802_11 (802.11)
0.000025 Báo hiệu (ns-3-ssid) [6.0 * 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Yêu cầu PGS (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000324 Acknowledgment RA:00:00:00:00:00:08
0.000402 Phản hồi của PGS GIÚP(0) :: Thành công
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Yêu cầu PGS (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000737 Acknowledgment RA:00:00:00:00:00:07
0.000824 Phản hồi của PGS GIÚP(0) :: Thành công
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Yêu cầu PGS (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001150 Acknowledgment RA:00:00:00:00:00:09
0.001273 Phản hồi của PGS GIÚP(0) :: Thành công
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Báo hiệu (ns-3-ssid) [6.0 * 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Báo hiệu (ns-3-ssid) [6.0 * 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Báo hiệu (ns-3-ssid) [6.0 * 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS

Bạn có thể thấy rằng loại liên kết bây giờ là 802.11 như bạn mong đợi. Bạn có thể có thể
hiểu điều gì đang xảy ra và tìm gói phản hồi và yêu cầu IP echo trong này
dấu vết. Chúng tôi để nó như một bài tập để phân tích cú pháp hoàn toàn kết xuất dấu vết.

Bây giờ, hãy nhìn vào tệp pcap ở phía bên phải của liên kết điểm-điểm,

$ tcpdump -nn -tt -r thứ ba-0-0.pcap

Một lần nữa, bạn sẽ thấy một số nội dung trông quen thuộc:

đọc từ tệp third-0-0.pcap, PPP kiểu liên kết (PPP)
2.008151 IP 10.1.3.3.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.026758 IP 10.1.2.4.9> 10.1.3.3.49153: UDP, chiều dài 1024

Đây là gói tiếng vọng đi từ trái sang phải (từ Wifi đến CSMA) và ngược lại qua
liên kết điểm-điểm.

Bây giờ, hãy nhìn vào tệp pcap ở phía bên phải của liên kết điểm-điểm,

$ tcpdump -nn -tt -r thứ ba-1-0.pcap

Một lần nữa, bạn sẽ thấy một số nội dung trông quen thuộc:

đọc từ tệp third-1-0.pcap, PPP kiểu liên kết (PPP)
2.011837 IP 10.1.3.3.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.023072 IP 10.1.2.4.9> 10.1.3.3.49153: UDP, chiều dài 1024

Đây cũng là gói tiếng vọng đi từ trái sang phải (từ Wifi đến CSMA) và quay lại một lần nữa
qua liên kết điểm-điểm với thời gian hơi khác như bạn có thể mong đợi.

Máy chủ echo nằm trên mạng CSMA, chúng ta hãy xem xét dấu vết bừa bãi ở đó:

$ tcpdump -nn -tt -r thứ ba-1-1.pcap

Bạn sẽ thấy một số nội dung trông quen thuộc:

đọc từ tệp thứ ba-1-1.pcap, loại liên kết EN10MB (Ethernet)
2.017837 ARP, Yêu cầu ai-có 10.1.2.4 (ff: ff: ff: ff: ff: ff) cho 10.1.2.1, độ dài 50
2.017861 ARP, Reply 10.1.2.4 is-at 00: 00: 00: 00: 00: 06, độ dài 50
2.017861 IP 10.1.3.3.49153> 10.1.2.4.9: UDP, chiều dài 1024
2.022966 ARP, Yêu cầu ai-có 10.1.2.1 (ff: ff: ff: ff: ff: ff) cho 10.1.2.4, độ dài 50
2.022966 ARP, Reply 10.1.2.1 is-at 00: 00: 00: 00: 00: 03, độ dài 50
2.023072 IP 10.1.2.4.9> 10.1.3.3.49153: UDP, chiều dài 1024

Điều này nên được dễ dàng hiểu. Nếu bạn đã quên, hãy quay lại và xem lại cuộc thảo luận
in thứ hai.cc. Đây là cùng một trình tự.

Bây giờ, chúng tôi đã dành rất nhiều thời gian để thiết lập các mô hình di động cho mạng không dây và vì vậy nó
sẽ thật tiếc nếu kết thúc mà không cho thấy rằng các nút STA đang thực sự di chuyển
xung quanh trong quá trình mô phỏng. Hãy làm điều này bằng cách kết nối với Tính di độngMô hình khóa học mơ ước
thay đổi nguồn vết. Đây chỉ là một cái nhìn sơ lược về phần theo dõi chi tiết
sắp tới, nhưng đây có vẻ là một nơi rất tốt để lấy ví dụ.

Như đã đề cập trong phần "Tinh chỉnh ns-3", ns-3 hệ thống truy tìm được chia thành dấu vết
nguồn và vết chìm, và chúng tôi cung cấp các chức năng để kết nối hai nguồn. Chúng tôi sẽ sử dụng
mô hình di động được xác định trước khóa học thay đổi nguồn theo dõi để tạo ra các sự kiện theo dõi. chúng tôi
sẽ cần phải viết một dấu vết chìm để kết nối với nguồn đó sẽ hiển thị một số
thông tin cho chúng tôi. Mặc dù có tiếng là khó, nhưng nó thực sự khá đơn giản.
Ngay trước chương trình chính của cào / mythird.cc script (tức là, chỉ sau
NS_LOG_COMPONENT_DEFINE câu lệnh), thêm chức năng sau:

làm mất hiệu lực
CourseChange (std :: string context, Ptr mô hình)
{
Vị trí véc tơ = model-> GetPosition ();
NS_LOG_UNCOND (ngữ cảnh <
"x =" << position.x << ", y =" << position.y);
}

Mã này chỉ lấy thông tin vị trí từ mô hình di động và vô điều kiện
ghi lại vị trí x và y của nút. Chúng tôi sẽ sắp xếp để chức năng này được
được gọi mỗi khi nút không dây có máy khách echo thay đổi vị trí của nó. Chúng tôi làm điều này
bằng cách sử dụng Cấu hình :: Kết nối chức năng. Chỉ thêm các dòng mã sau vào tập lệnh
trước Trình mô phỏng :: Chạy gọi.

std :: ostringstream oss;
oss <
"/ NodeList /" << wifiStaNodes.Get (nWifi - 1) -> GetId () <
"/ $ ns3 :: MobilityModel / CourseChange";

Cấu hình :: Kết nối (oss.str (), MakeCallback (& ​​CourseChange));

Những gì chúng tôi làm ở đây là tạo một chuỗi chứa đường dẫn không gian tên theo dõi của sự kiện
mà chúng tôi muốn kết nối. Đầu tiên, chúng tôi phải tìm ra nút nào chúng tôi muốn sử dụng
các NhậnId như đã mô tả trước đó. Trong trường hợp số lượng CSMA mặc định và
các nút không dây, đây hóa ra là nút bảy và đường dẫn không gian tên theo dõi đến
mô hình di động sẽ trông như thế nào,

/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange

Dựa trên thảo luận trong phần theo dõi, bạn có thể suy ra rằng đường dẫn theo dõi này
tham chiếu đến nút thứ bảy trong NodeList toàn cầu. Nó chỉ định những gì được gọi là
đối tượng tổng hợp của loại ns3 :: MobilityModel. Tiền tố ký hiệu đô la ngụ ý rằng
MobilityModel được tổng hợp thành nút bảy. Thành phần cuối cùng của đường dẫn có nghĩa là chúng ta
đang kết nối với sự kiện "CourseChange" của mô hình đó.

Chúng tôi tạo kết nối giữa nguồn theo dõi trong nút bảy với bồn theo dõi của chúng tôi bằng cách gọi
Cấu hình :: Kết nối và chuyển đường dẫn không gian tên này. Khi điều này được thực hiện, mọi khóa học sẽ thay đổi
sự kiện trên nút bảy sẽ được nối vào bồn theo dõi của chúng tôi, từ đó sẽ in ra
vị trí mới.

Nếu bây giờ bạn chạy mô phỏng, bạn sẽ thấy các thay đổi của khóa học được hiển thị khi chúng xảy ra.

'xây dựng' đã hoàn thành thành công (5.989 giây)
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10, y = 0
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.3841, y = 0.923277
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.2049, y = 1.90708
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.8136, y = 1.11368
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.8452, y = 2.11318
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.9797, y = 3.10409
Tại thời điểm khách hàng 2s đã gửi 1024 byte đến 10.1.2.4 cổng 9
Tại thời điểm máy chủ 2.01796s nhận được 1024 byte từ cổng 10.1.3.3 49153
Tại thời điểm máy chủ 2.01796s đã gửi 1024 byte đến cổng 10.1.3.3 49153
Tại thời điểm máy khách 2.03364s nhận được 1024 byte từ cổng 10.1.2.4 cổng 9
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 11.3273, y = 4.04175
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 12.013, y = 4.76955
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 12.4317, y = 5.67771
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 11.4607, y = 5.91681
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 12.0155, y = 6.74878
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 13.0076, y = 6.62336
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 12.6285, y = 5.698
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 13.32, y = 4.97559
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 13.1134, y = 3.99715
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 13.8359, y = 4.68851
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 13.5953, y = 3.71789
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 12.7595, y = 4.26688
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 11.7629, y = 4.34913
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 11.2292, y = 5.19485
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 10.2344, y = 5.09394
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 9.3601, y = 4.60846
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 8.40025, y = 4.32795
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 9.14292, y = 4.99761
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 9.08299, y = 5.99581
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 8.26068, y = 5.42677
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 8.35917, y = 6.42191
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 7.66805, y = 7.14466
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 6.71414, y = 6.84456
/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 6.42489, y = 7.80181

GIAO DỊCH


Tiểu sử
Như đã đề cập trong usingTracingSystem, toàn bộ điểm của việc chạy một ns-3 mô phỏng là để
tạo ra đầu ra cho nghiên cứu. Bạn có hai chiến lược cơ bản để có được đầu ra từ ns-3:
sử dụng cơ chế đầu ra hàng loạt được xác định trước chung và phân tích cú pháp nội dung của chúng để trích xuất
thông tin thú vị; hoặc bằng cách nào đó phát triển một cơ chế đầu ra truyền tải chính xác
(và có lẽ chỉ) thông tin muốn.

Sử dụng cơ chế đầu ra hàng loạt được xác định trước có lợi thế là không yêu cầu bất kỳ thay đổi nào đối với
ns-3, nhưng nó có thể yêu cầu viết tập lệnh để phân tích cú pháp và lọc dữ liệu quan tâm. Thường,
PCAP hoặc NS_LOG thông báo đầu ra được thu thập trong quá trình chạy mô phỏng và chạy riêng
thông qua các tập lệnh sử dụng grep, khát or ôi để phân tích cú pháp các tin nhắn và giảm bớt và chuyển đổi
dữ liệu ở dạng có thể quản lý được. Các chương trình phải được viết để thực hiện chuyển đổi, vì vậy điều này
không đến miễn phí. NS_LOG đầu ra không được coi là một phần của ns-3 API và có thể
thay đổi mà không có cảnh báo giữa các lần phát hành. Ngoài, NS_LOG đầu ra chỉ có sẵn trong
bản dựng gỡ lỗi, vì vậy dựa vào nó sẽ áp dụng hình phạt về hiệu suất. Tất nhiên, nếu
thông tin quan tâm không tồn tại trong bất kỳ cơ chế đầu ra nào được xác định trước, điều này
cách tiếp cận không thành công.

Nếu bạn cần thêm một số thông tin nhỏ vào các cơ chế hàng loạt được xác định trước, điều này có thể
chắc chắn được thực hiện; và nếu bạn sử dụng một trong những ns-3 cơ chế, bạn có thể nhận được mã của mình được thêm vào
như một đóng góp.

ns-3 cung cấp một cơ chế khác, được gọi là Truy tìm, tránh một số vấn đề vốn có
trong các cơ chế đầu ra số lượng lớn. Nó có một số lợi thế quan trọng. Đầu tiên, bạn có thể
giảm lượng dữ liệu bạn phải quản lý bằng cách chỉ theo dõi các sự kiện mà bạn quan tâm
(đối với các mô phỏng lớn, việc lưu trữ mọi thứ vào đĩa để xử lý hậu kỳ có thể tạo ra I / O
nút thắt cổ chai). Thứ hai, nếu bạn sử dụng phương pháp này, bạn có thể kiểm soát định dạng của đầu ra
trực tiếp để bạn tránh bước xử lý sau với khát, ôi, perl or mãng xà các tập lệnh. Nếu như
bạn mong muốn, đầu ra của bạn có thể được định dạng trực tiếp thành một biểu mẫu được gnuplot chấp nhận, cho
ví dụ (xem thêm GnuplotHelper). Bạn có thể thêm các móc vào lõi, sau đó có thể
được người dùng khác truy cập, nhưng sẽ không cung cấp thông tin trừ khi được yêu cầu rõ ràng
làm như vậy. Vì những lý do này, chúng tôi tin rằng ns-3 hệ thống theo dõi là cách tốt nhất để có được
thông tin từ mô phỏng và do đó cũng là một trong những cơ chế quan trọng nhất
hiểu trong ns-3.

không nhọn Dụng 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à
để chỉ in thông tin trực tiếp ra đầu ra tiêu chuẩn, như trong:

#bao gồm
...
làm mất hiệu lực
Một số chức năng (void)
{
uint32_t x = SOME_INTERESTING_VALUE;
...
std :: cout << "Giá trị của x là" << x << std :: endl;
...
}

Không ai ngăn cản bạn đi sâu vào cốt lõi của ns-3 và thêm bản in
các câu lệnh. Điều này cực kỳ dễ thực hiện và sau tất cả, bạn có toàn quyền kiểm soát
riêng ns-3 ngành. Điều này có lẽ sẽ không được hài lòng về lâu dài
hạn, mặc dù.

Khi số lượng câu lệnh in tăng lên trong các chương trình của bạn, nhiệm vụ xử lý
số lượng lớn đầu ra sẽ ngày càng phức tạp hơn. Cuối cùng, bạn có thể cảm thấy
nhu cầu kiểm soát thông tin nào đang được in theo một cách nào đó, có lẽ bằng cách bật
và tắt một số danh mục bản in nhất định hoặc tăng hoặc giảm số lượng
thông tin bạn muốn. Nếu bạn tiếp tục đi theo con đường này, bạn có thể phát hiện ra rằng bạn có
thực hiện lại NS_LOG cơ chế (xem Sử dụng Đăng ký). Để tránh điều đó, một trong những
điều đầu tiên bạn có thể cân nhắc là sử dụng NS_LOG chính nó.

Chúng tôi đã đề cập ở trên rằng một cách để lấy thông tin ra khỏi ns-3 là để phân tích cú pháp hiện có NS_LOG
đầu ra cho thông tin thú vị. Nếu bạn phát hiện ra rằng một số thông tin nhỏ bạn
nhu cầu không có trong đầu ra nhật ký hiện có, bạn có thể chỉnh sửa cốt lõi của ns-3 và chỉ cần thêm
thông tin thú vị của bạn đến luồng đầu ra. Bây giờ, điều này chắc chắn tốt hơn
thêm các câu lệnh in của riêng bạn vì nó theo sau ns-3 quy ước mã hóa và có thể
có khả năng hữu ích cho người khác như một bản vá cho cốt lõi hiện có.

Hãy chọn một ví dụ ngẫu nhiên. Nếu bạn muốn thêm nhiều nhật ký vào ns-3 Ổ cắm TCP
(tcp-socket-base.cc) bạn chỉ có thể thêm một thông báo mới trong quá trình triển khai. Để ý
trong đó TcpSocketBase :: ReceivedAck () không có thông báo nhật ký cho trường hợp không có ACK. Bạn
có thể chỉ cần thêm một, thay đổi mã. Đây là bản gốc:

/ ** Xử lý ACK mới nhận được * /
làm mất hiệu lực
TcpSocketBase :: ReceivedAck (Ptr gói, const TcpHeader & tcpHeader)
{
NS_LOG_FUNCTION (this << tcpHeader);

// Đã nhận ACK. So sánh số ACK với seqno cao nhất không được kiểm tra
if (0 == (tcpHeader.GetFlags () & TcpHeader :: ACK))
{// Bỏ qua nếu không có cờ ACK
}
...

Để ghi lại trường hợp không có ACK, bạn có thể thêm một NS_LOG_LOGIC trong if nội dung câu lệnh:

/ ** Xử lý ACK mới nhận được * /
làm mất hiệu lực
TcpSocketBase :: ReceivedAck (Ptr gói, const TcpHeader & tcpHeader)
{
NS_LOG_FUNCTION (this << tcpHeader);

// Đã nhận ACK. So sánh số ACK với seqno cao nhất không được kiểm tra
if (0 == (tcpHeader.GetFlags () & TcpHeader :: ACK))
{// Bỏ qua nếu không có cờ ACK
NS_LOG_LOGIC ("TcpSocketBase" << this << "không có cờ ACK");
}
...

Điều này thoạt nhìn có vẻ khá đơn giản và thỏa mãn, nhưng điều cần xem xét là
mà bạn sẽ viết mã để thêm NS_LOG tuyên bố và bạn cũng sẽ phải viết
mã (như trong grep, khát or ôi script) để phân tích cú pháp đầu ra nhật ký nhằm tách biệt
thông tin. Điều này là do mặc dù bạn có một số quyền kiểm soát đối với những gì được đầu ra bởi
hệ thống ghi nhật ký, bạn chỉ có quyền kiểm soát ở cấp độ thành phần nhật ký, thường là
toàn bộ tệp mã nguồn.

Nếu bạn đang thêm mã vào một mô-đun hiện có, bạn cũng sẽ phải sống với đầu ra
mà mọi nhà phát triển khác đều thấy thú vị. Bạn có thể tìm thấy điều đó để có được
một lượng nhỏ thông tin bạn cần, bạn có thể phải lướt qua một lượng lớn
tin nhắn không liên quan mà bạn không quan tâm. Bạn có thể bị buộc phải lưu nhật ký lớn
tệp vào đĩa và xử lý chúng thành một vài dòng bất cứ khi nào bạn muốn làm bất cứ điều gì.

Vì không có đảm bảo nào trong ns-3 về sự ổn định của NS_LOG đầu ra, bạn cũng có thể
khám phá rằng các phần đầu ra nhật ký mà bạn phụ thuộc vào biến mất hoặc thay đổi giữa
các bản phát hành. Nếu bạn phụ thuộc vào cấu trúc của đầu ra, bạn có thể thấy các thông báo khác đang
được thêm vào hoặc bị xóa có thể ảnh hưởng đến mã phân tích cú pháp của bạn.

Ngoài ra, thẻ cào NS_LOG đầu ra chỉ khả dụng trong các bản dựng gỡ lỗi, bạn không thể lấy đầu ra nhật ký từ
các bản dựng được tối ưu hóa, chạy nhanh gấp đôi. Phụ thuộc vào NS_LOG áp đặt một buổi biểu diễn
hình phạt.

Vì những lý do này, chúng tôi coi các bản in để std :: coutNS_LOG tin nhắn nhanh chóng và
những cách bẩn thỉu để lấy thêm thông tin từ ns-3, nhưng không thích hợp cho những công việc nghiêm túc.

Mong muốn có một cơ sở ổn định bằng cách sử dụng các API ổn định cho phép một người có thể tiếp cận
hệ thống cốt lõi và chỉ lấy thông tin cần thiết. Nó là mong muốn để có thể làm
điều này 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 mã 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 để người dùng không phải chủ động dò tìm trong hệ thống để tìm kiếm
điều.

Sản phẩm 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
Thuộc tính và Config hệ thống con cho phép các tình huống sử dụng tương đối đơn giản.

Giới thiệu chung
Sản phẩm 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à
dấu vết chìm, cùng với một cơ chế đồng nhất để kết nối nguồn với bồn rửa.

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 một nguồn theo dõi. Mỗi khi cửa sổ tắc nghẽn thay đổi dấu vết kết nối
bồn rửa được thông báo với giá trị cũ và mới.

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 dữ liệu và dấu vết là người tiêu dùng. Sự phân chia rõ ràng này cho phép
số lượng các nguồn theo dõi đượ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. Chèn các nguồn theo dõi giới thiệu một quá trình thực thi rất nhỏ
trên khô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 nghĩ về nguồn theo dõi như một loại liên kết thông tin điểm - đa điểm. Ma cua ban
tìm kiếm các sự kiện theo dõi từ một đoạn mã lõi cụ thể có thể cùng tồn tại một cách vui vẻ với
mã khác làm điều gì đó hoàn toàn khác với cùng một thông tin.

Trừ khi người dùng kết nối bộ lưu dấu vết với một trong những nguồn này, không có gì là đầu ra. Bằng cách sử dụng
hệ thống theo dõi, cả bạn và những người khác được kết nối với cùng một nguồn theo dõi đang nhận được
chính xác những gì họ muốn và chỉ những gì họ muốn ngoài hệ thống. Cả hai người đều không
tác động đến bất kỳ người dùng nào khác bằng cách thay đổi thông tin nào được hệ thống xuất ra. nếu bạn
tình cờ thêm một nguồn theo dõi, công việc của bạn với tư cách là một công dân nguồn mở tốt có thể cho phép người khác
người dùng cung cấp các tiện ích mới có lẽ rất hữu ích về tổng thể, mà không tạo ra bất kỳ
thay đổi để ns-3 cốt lõi.

Đơn giản Ví dụ
Hãy dành một vài phút và xem qua một ví dụ truy tìm đơn giản. Chúng tôi sẽ cần
một chút thông tin cơ bản về Callbacks để hiểu điều gì đang xảy ra trong ví dụ này, vì vậy chúng tôi
phải đi đường vòng nhỏ ngay.

Gọi lại
Mục tiêu của hệ thống Gọi lại trong ns-3 là cho phép một đoạn mã gọi một hàm
(hoặc phương thức trong C ++) mà không có bất kỳ phụ thuộc liên 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ố kiểu chuyển hướng - bạn coi địa chỉ của hàm được gọi là
Biến đổi. Biến này được gọi là biến con trỏ đến hàm. Mối quan hệ
giữa hàm và con trỏ đến hàm thực sự không khác gì so với đối tượng và
con trỏ đến đối tượng.

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

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

(Nhưng hãy đọc C ++ - Câu hỏi thường gặp Phần 33 trước khi viết mã như thế này!) Bạn nhận được gì từ điều này
là một biến được đặt tên đơn giản pfi được khởi tạo thành 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 hàm với
phù hợp với chữ ký. Trong trường hợp này, bạn có thể cung cấp một hàm giống như sau:

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 bạn:

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);

Điều này có vẻ như bạn đang gọi một hàm có tên pfi, nhưng trình biên dịch đủ thông minh để
biết gọi thông qua biến pfi gián tiếp đến chức năng chức năng của tôi.

Về mặt khái niệm, đây gần như là chính xác cách thức hoạt động của hệ thống truy tìm. Về cơ bản, một dấu vết
bồn rửa is một cuộc gọi lại. Khi một bể chứa dấu vết thể hiện sự quan tâm đến việc nhận các sự kiện theo dõi, nó
tự thêm nó dưới dạng Callback vào danh sách các Callback do nguồn theo dõi nắm giữ bên trong.
Khi một sự kiện thú vị xảy ra, nguồn theo dõi sẽ gọi nó nhà điều hành(...) cung cấp
không hoặc nhiều đối số. Các nhà điều hành(...) cuối cùng đi vào hệ thống và
thực hiện một điều gì đó đáng chú ý như cuộc gọi gián tiếp mà bạn vừa thấy, cung cấp không hoặc nhiều hơn
các tham số, giống như lệnh gọi tới pfi ở trên đã truyền một tham số cho hàm mục tiêu
chức năng của tôi.

Sự khác biệt quan trọng mà hệ thống truy tìm bổ sung là đối với mỗi nguồn theo dõi ở đó
là danh sách nội bộ của các cuộc gọi lại. Thay vì chỉ thực hiện một cuộc gọi gián tiếp, một dấu vết
nguồn có thể gọi nhiều Gọi lại. Khi một dấu vết chìm thể hiện sự quan tâm đến
thông báo từ một nguồn theo dõi, về cơ bản nó chỉ sắp xếp để thêm chức năng của riêng mình vào
danh sách gọi lại.

Nếu bạn muốn biết thêm chi tiết về cách thực sự sắp xếp điều này trong ns-3, cảm thấy
miễn phí sử dụng phần Gọi lại của ns-3 Hướng dẫn sử dụng.

Hướng dẫn: thứ tư.cc
Chúng tôi đã cung cấp một số mã để triển khai những gì thực sự là ví dụ đơn giản nhất về theo dõi
có thể được lắp ráp. Bạn có thể tìm thấy mã này trong thư mục hướng dẫn như thứ tư.cc.
Hãy xem qua nó:

/ * - * - Chế độ: C ++; c-file-style: "gnu"; thụt lề-tabs-mode: nil; - * - * /
/*
* Chương trình này là phần mềm miễn phí; bạn có thể phân phối lại nó và / hoặc sửa đổi
* nó theo các điều khoản của Giấy phép Công cộng GNU phiên bản 2 như
* được xuất bản bởi Free Software Foundation;
*
* Chương trình này được phân phối với hy vọng rằng nó sẽ hữu ích,
* nhưng KHÔNG CÓ BẤT KỲ BẢO HÀNH NÀO; mà không có bảo hành ngụ ý
* KHẢ NĂNG LAO ĐỘNG hoặc PHÙ HỢP VỚI MỤC ĐÍCH CỤ THỂ. Xem
* Giấy phép Công cộng GNU để biết thêm chi tiết.
*
* Bạn đáng lẽ đã nhận được một bản sao của Giấy phép Công cộng GNU
* cùng với chương trình này; nếu không, hãy viết thư cho Phần mềm Miễn phí
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 Hoa Kỳ
*/

#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;

Hầu hết mã này sẽ khá quen thuộc với bạn. 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, vì vậy bạn sẽ cần phải bao gồm chúng.
Hai phần đầu tiên bao gồm ở trên mang lại các khai báo cho các hệ thống đó một cách rõ ràng. Bạn
có thể sử dụng tiêu đề mô-đun cốt lõi để tải mọi thứ cùng một lúc, nhưng chúng tôi thực hiện bao gồm
rõ ràng ở đây để minh họa tất cả điều này thực sự đơn giản như thế nào.

Tập tin, truy tìm giá trị.h mang lại các khai báo bắt buộc để 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ể vượt qua
đối tượng xung quanh chính nó, thay vì truyền địa chỉ của đối tượng. Tất cả những điều này thực sự là gì
có nghĩa là bạn sẽ có thể theo dõi tất cả các thay đổi được thực hiện đối với TracedValue một cách thực sự
cách đơn giản.

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 theo dõi tồn tại. Đoạn mã tiếp theo
khai báo và định nghĩa một Đối tượng đơn giản mà chúng ta có thể làm việc.

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),
"ns3 :: Traced :: Value :: Int32Callback")
;
trả lại tid;
}

Đối tượng của tôi () {}
TracedValue m_myInt;
};

Hai dòng mã quan trọng, ở trên, liên quan đến truy tìm là .AddTraceSource
Giá trị truy tìm khai báo m_myInt.

Sản phẩm .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 thông qua hệ thống Config. Đối số đầu tiên là tên cho dấu vết này
nguồn, làm cho nó hiển thị trong hệ thống Cấu hình. Đối số thứ hai là một chuỗi trợ giúp.
Bây giờ hãy nhìn vào đối số thứ ba, trên thực tế, tập trung vào đối số của đối số thứ ba:
& MyObject :: m_myInt. Đây là TracedValue đang được thêm vào lớp; nó là
luôn là thành viên dữ liệu lớp. (Đối số cuối cùng là tên của một đánh máy cho
Loại TracedValue, dưới dạng một chuỗi. Điều này được sử dụng để tạo tài liệu cho chính xác
Chữ ký hàm gọi lại, đặc biệt hữu ích đối với các loại
Gọi lại.)

Sản phẩm TracedValue <> khai báo cung cấp cơ sở hạ tầng thúc đẩy cuộc gọi lại
quy trình. Bất kỳ lúc nào giá trị cơ bản bị thay đổi, cơ chế TracedValue sẽ cung cấp
cả giá trị cũ và mới của biến đó, trong trường hợp này là int32_t giá trị. Dấu vết
chức năng chìm cho TracedValue này sẽ cần chữ ký

void (* TracedValueCallback) (const int32_t oldValue, const int32_t newValue);

Tất cả các bồn chứa dấu vết móc nguồn dấu vết này đều phải có chữ ký này. Chúng ta sẽ thảo luận bên dưới
cách bạn có thể xác định chữ ký gọi lại được yêu cầu trong các trường hợp khác.

Chắc chắn rồi, tiếp tục qua thứ tư.cc chúng tôi thấy:

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

Đây là định nghĩa của một bồn rửa dấu vết phù hợp. Nó tương ứng trực tiếp với cuộc gọi lại
chữ ký chức năng. Khi nó được kết nối, hàm này sẽ được gọi bất cứ khi nào
Giá trị truy tìm thay đổi.

Bây giờ chúng ta đã thấy nguồn gốc và dấu vết chìm. Những gì còn lại là mã để kết nối
nguồn đến bồn rửa, xảy ra trong chính:

int
main (int argc, char * argv [])
{
Ptr myObject = CreateObject ();
myObject-> TraceConnectWithoutContext ("MyInteger", MakeCallback (& ​​IntTrace));

myObject-> m_myInt = 1234;
}

Ở đây, trước tiên chúng ta tạo cá thể MyObject mà nguồn theo dõi tồn tại.

Bước tiếp theo, TraceConnectWithoutContext, tạo thành kết nối giữa dấu vết
nguồn và dấu vết chìm. Đối số đầu tiên chỉ là tên nguồn theo dõi "MyInteger"
chúng ta đã thấy ở trên. Chú ý gọi lại chức năng mẫu. Chức năng này thực hiện điều kỳ diệu
cần thiết để tạo nền tảng ns-3 Gọi lại đối tượng và liên kết nó với hàm
IntTrace. Dấu vếtKết nối tạo sự liên kết giữa chức năng đã cung cấp của bạn và
quá tải nhà điều hành() trong biến đã theo dõi được tham chiếu bởi Thuộc tính "MyInteger".
Sau khi liên kết này được thực hiện, nguồn theo dõi sẽ "kích hoạt" lệnh gọi lại đã cung cấp của bạn
chức năng.

Tất nhiên, mã để làm cho tất cả những điều này xảy ra là không tầm thường, nhưng bản chất là
bạn đang sắp xếp cho một cái gì đó trông giống như pfi () ví dụ ở trên được gọi là
bằng nguồn theo dõi. Tuyên bố của TracedValue m_myInt; trong Đối tượng
chính nó thực hiện phép thuật cần thiết để cung cấp các toán tử gán quá tải sẽ
sử dụng nhà điều hành() để thực sự gọi Callback với các tham số mong muốn. Các
.AddTraceSource thực hiện phép thuật để kết nối Gọi lại với hệ thống Cấu hình, và
TraceConnectWithoutContext thực hiện phép thuật để kết nối chức năng của bạn với dấu vết
nguồn, được chỉ định bởi Tên thuộc tính.

Bây giờ chúng ta hãy bỏ qua một chút về ngữ cảnh.

Cuối cùng, dòng gán giá trị cho m_myInt:

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ố.

từ m_myInt là một Giá trị truy tìm, toán tử này được định nghĩa để thực hiện một lệnh gọi lại
trả về void và nhận hai giá trị 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 lệnh gọi lại
chức năng 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 một cách thức kết nối các nguồn xác định dấu vết để tìm vết chìm.
Hành động "đánh" nguồn theo dõi đang thực thi một toán tử trên nguồn theo dõi mà
kích hoạt các cuộc gọi lại. Điều này dẫn đến các cuộc gọi lại chìm theo dấu vết những người đăng ký quan tâm đến
nguồn được gọi với các tham số được cung cấp bởi nguồn.

Nếu bây giờ bạn xây dựng và chạy ví dụ này,

$ ./waf --run thứ tư

bạn sẽ thấy đầu ra từ IntTrace chức năng thực thi ngay khi nguồn theo dõi là
đánh:

Theo dõi từ 0 đến 1234

Khi chúng tôi thực thi mã, myObject-> m_myInt = 1234;, nguồn theo dõi đã kích hoạt và
đã tự động cung cấp các giá trị trước và sau cho bộ lưu dấu vết. Chức năng
IntTrace sau đó in nó ra đầu ra tiêu chuẩn.

Kết nối với Config
Sản phẩm 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 để chọn một dấu vết
nguồn trong hệ thống sử dụng cái được gọi là Config con đường. Chúng tôi đã thấy một ví dụ về điều này trong
phần trước, nơi chúng tôi kết nối sự kiện "CourseChange" khi chúng tôi đang thử nghiệm
thứ ba.cc.

Nhớ lại rằng chúng tôi đã xác định một dấu vết chìm để in thông tin thay đổi khóa học từ tính di động
mô hình mô phỏng của chúng tôi. Bây giờ sẽ rõ ràng hơn rất nhiều cho bạn chức năng này là gì
đang làm:

làm mất hiệu lực
CourseChange (std :: string context, Ptr mô hình)
{
Vị trí véc tơ = model-> GetPosition ();
NS_LOG_UNCOND (ngữ cảnh <
"x =" << position.x << ", y =" << position.y);
}

Khi chúng tôi kết nối nguồn theo dõi "CourseChange" với bồn theo dõi ở trên, chúng tôi đã sử dụng
Đường dẫn cấu hình để chỉ định nguồn khi chúng tôi sắp xếp kết nối giữa các đường dẫn được xác định trước
nguồn theo dõi và dấu vết chìm mới:

std :: ostringstream oss;
oss << "/ NodeList /"
<< wifiStaNodes.Get (nWifi - 1) -> GetId ()
<< "/ $ ns3 :: MobilityModel / CourseChange";

Cấu hình :: Kết nối (oss.str (), MakeCallback (& ​​CourseChange));

Hãy thử và tìm hiểu những gì đôi khi được coi là mã tương đối bí ẩn.
Với mục đích thảo luận, giả sử rằng số Node được trả về bởi GetId () is
"7". Trong trường hợp này, đường dẫn trên hóa ra là

"/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange"

Phân đoạn cuối cùng của đường dẫn cấu hình phải là đặc tính của một Đối tượng. Trong thực tế, nếu bạn có
một con trỏ đến Đối tượng có "CourseChange" đặc tính hữu ích, bạn có thể viết cái này
giống như chúng ta đã làm trong ví dụ trước. Bây giờ bạn biết rằng chúng tôi thường lưu trữ
trỏ đến của chúng tôi Nodes trong NodeContainer. bên trong thứ ba.cc ví dụ, các nút quan tâm
được lưu trữ trong wifiStaNodes NodeContainer. Trên thực tế, trong khi đặt con đường lại với nhau,
chúng tôi đã sử dụng thùng chứa này để có được một Ptr mà chúng tôi thường gọi GetId (). Chúng ta có thể có
đã sử dụng cái này Ptr để gọi trực tiếp một phương thức Connect:

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject-> TraceConnectWithoutContext ("CourseChange", MakeCallback (& ​​CourseChange));

Trong tạp chí thứ ba.cc ví dụ, chúng tôi thực sự muốn một "ngữ cảnh" bổ sung được phân phối cùng
với các tham số Gọi lại (sẽ được giải thích bên dưới) để chúng tôi thực sự có thể sử dụng
mã tương đương sau:

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject-> TraceConnect ("CourseChange", MakeCallback (& ​​CourseChange));

Nó chỉ ra rằng mã nội bộ cho Cấu hình :: ConnectWithoutContextCấu hình :: Kết nối
thực sự tìm thấy một Ptr và gọi cho thích hợp Dấu vếtKết nối phương pháp ở mức thấp nhất
cấp độ.

Sản phẩm Config các hàm sử dụng một đường dẫn đại diện cho một chuỗi Đối tượng con trỏ. Mỗi phân đoạn
của một đường dẫn tương ứng với một Thuộc tính Đối tượng. Phân đoạn cuối cùng là Thuộc tính của
sở thích và các phân đoạn trước phải được nhập để chứa hoặc tìm Đối tượng. Các Config
phân tích cú pháp và "đi" con đường này cho đến khi nó đi đến đoạn cuối cùng của con đường. Sau đó nó
giải thích phân đoạn cuối cùng là một đặc tính trên Đối tượng cuối cùng mà nó tìm thấy trong khi đi bộ
đường dẫn. Các Config sau đó gọi hàm thích hợp Dấu vếtKết nối or
TraceConnectWithoutContext phương thức trên đối tượng cuối cùng. Hãy xem điều gì sẽ xảy ra sau một chút
chi tiết hơn khi con đường trên được đi bộ.

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 / 7" đề cập đến Node thứ tám trong danh sách các nút được tạo trong quá trình mô phỏng
(chỉ số nhớ lại bắt đầu lúc 0 '). T tài liệu tham khảo is thực sự a `` Ptr ` và vì vậy là 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 của ns-3 Hướng dẫn sử dụng, chúng tôi sử dụng rộng rãi
tập hợp đối tượng. Điều này cho phép chúng tôi hình thành một liên kết giữa các Đối tượng khác nhau
mà không cần xây dựng một cây kế thừa phức tạp hoặc xác định trước những đối tượng nào sẽ là một phần
của một Node. Mỗi Đối tượng trong một Tổng thể có thể được tiếp cận từ các Đối tượng khác.

Trong ví dụ của chúng tôi, đoạn đường tiếp theo đang được đi bắt đầu bằng ký tự "$". Cái này
chỉ ra cho hệ thống cấu hình rằng phân đoạn là tên của một loại đối tượng, vì vậy
Nhận đối tượng cuộc gọi nên được thực hiện tìm kiếm loại đó. Nó chỉ ra rằng Trợ giúp di động
Được dùng trong thứ ba.cc sắp xếp để Tổng hợp hoặc liên kết, một mô hình di động cho mỗi
không dây Nodes. Khi bạn thêm "$", bạn đang yêu cầu một Đối tượng khác có
có lẽ đã được tổng hợp trước đó. Bạn có thể coi đây là chuyển đổi con trỏ từ
Ptr ban đầu như được chỉ định bởi "/ NodeList / 7" cho mô hình di động liên quan của nó ---
thuộc loại nào ns3 :: MobilityModel. Nếu bạn quen thuộc với Nhận đối tượng, chúng tôi đã hỏi
hệ thống để thực hiện những việc sau:

Ptr MobileModel = node-> GetObject ()

Bây giờ chúng ta đang ở Đối tượng cuối cùng trong đường dẫn, vì vậy chúng ta chuyển sự chú ý đến các Thuộc tính của
Đối tượng đó. Các Tính di độngMô hình lớp định nghĩa một Thuộc tính được gọi là "CourseChange". Bạn có thể
thấy điều này bằng cách xem mã nguồn trong src / di động / model / di động-model.cc
tìm kiếm "CourseChange" trong trình soạn thảo yêu thích của bạn. Bạn nên tìm

.AddTraceSource ("CourseChange",
"Giá trị của vị trí và / hoặc vectơ vận tốc đã thay đổi",
MakeTraceSourceAccessor (& MobilityModel :: m_courseChangeTrace),
"ns3 :: MobilityModel :: CourseChangeCallback")

mà sẽ trông rất quen thuộc vào thời điểm này.

Nếu bạn tìm kiếm khai báo tương ứng của biến được truy tìm cơ bản trong
mô hình di động.h Bạn sẽ thấy

TracedCallback > m_courseChangeTrace;

Khai báo kiểu Truy tìmGọi lại xác định m_courseChangeTrace như một danh sách đặc biệt của
Các lệnh gọi lại có thể được nối bằng cách sử dụng các chức năng Cấu hình được mô tả ở trên. Các đánh máy cho
chữ ký hàm gọi lại cũng được xác định trong tệp tiêu đề:

void typedef (* CourseChangeCallback) (Ptr * người mẫu);

Sản phẩm Tính di độngMô hình lớp được thiết kế để trở thành lớp cơ sở cung cấp giao diện chung cho
tất cả các lớp con cụ thể. Nếu bạn tìm kiếm xuống cuối tệp, bạn sẽ thấy
phương pháp được xác định được gọi là NotifyCourseChange ():

làm mất hiệu lực
MobilityModel :: NotifyCourseChange (void) const
{
m_courseChangeTrace (this);
}

Các lớp có nguồn gốc sẽ gọi vào phương thức này bất cứ khi nào chúng thực hiện thay đổi khóa học để hỗ trợ
truy tìm. Phương thức này gọi nhà điều hành() trên cơ sở m_courseChangeTrace, Mà
đến lượt nó, sẽ gọi tất cả các Gọi lại đã đăng ký, gọi tất cả các dấu vết chìm
đã đăng ký quan tâm đến nguồn theo dõi bằng cách gọi một hàm Cấu hình.

Vì vậy, trong thứ ba.cc ví dụ mà chúng tôi đã xem xét, bất cứ khi nào thay đổi khóa học được thực hiện ở một trong các
RandomWalk2dMobilityMô hình các phiên bản được cài đặt, sẽ có một NotifyCourseChange () cuộc gọi
cái nào gọi đến Tính di độngMô hình lớp cơ sở. Như đã thấy ở trên, điều này gọi nhà điều hành()
on m_courseChangeTrace, do đó, gọi bất kỳ dấu vết đã đăng ký nào là chìm. Trong ví dụ,
mã duy nhất đăng ký sở thích là mã cung cấp đường dẫn Cấu hình.
Vì vậy, Khóa họcThay đổi hàm được nối từ Nút số bảy sẽ là
chỉ Callback được gọi.

Mảnh ghép cuối cùng của câu đố là "bối cảnh". Nhớ lại rằng chúng tôi đã thấy một kết quả tìm kiếm
một cái gì đó như sau từ thứ ba.cc:

/ NodeList / 7 / $ ns3 :: MobilityModel / CourseChange x = 7.27897, y =
2.22677

Phần đầu tiên của đầu ra là ngữ cảnh. Nó chỉ đơn giản là con đường mà qua đó
mã cấu hình định vị nguồn theo dõi. Trong trường hợp chúng tôi đã xem xét, có thể có
bất kỳ số lượng nguồn theo dõi nào trong hệ thống tương ứng với bất kỳ số lượng nút nào có
mô hình di động. Cần phải có một số cách để xác định nguồn theo dõi nào thực sự là
cái đã kích hoạt Gọi lại. Cách dễ dàng là kết nối với Cấu hình :: Kết nối, thay thế
of Cấu hình :: ConnectWithoutContext.

Tìm kiếm nguồn
Câu hỏi đầu tiên chắc chắn sẽ xuất hiện đối với những người dùng mới của hệ thống Truy tìm là, "Được chứ,
I Biết việc này phải be theo dõi nguồn in các mô phỏng cốt lõi, nhưng làm thế nào do I tìm ra
theo dõi nguồn đang có sẵn đến tôi?"

Câu hỏi thứ hai là, "Được chứ, I tìm thấy a theo dõi nguồn, làm thế nào do I con số ra các Config con đường
đến sử dụng khi nào I kết nối đến nó?"

Câu hỏi thứ ba là, "Được chứ, I tìm thấy a theo dõi nguồn các Config CON ĐƯỜNG làm thế nào do I con số
ra các trở lại kiểu chính thức đối số of my gọi lại chức năng nhu cầu đến là?"

Câu hỏi thứ tư là, "Được chứ, I đã đánh máy việc này tất cả các in điều này vô cùng kỳ quái lôi
thông điệp, in các thế giới làm it nghĩa là?"

Chúng tôi sẽ lần lượt giải quyết từng vấn đề này.

Có Sẵn nguồn
Đuợc, I Biết việc này phải be theo dõi nguồn in các mô phỏng cốt lõi, nhưng làm thế nào do I tìm
ra theo dõi nguồn đang có sẵn đến tôi?

Câu trả lời cho câu hỏi đầu tiên được tìm thấy trong ns-3 Tài liệu API. Nếu bạn đi đến
trang web dự án, ns-3 dự án, bạn sẽ tìm thấy một liên kết đến "Tài liệu" trong điều hướng
quán ba. Nếu bạn chọn liên kết này, bạn sẽ được đưa đến trang tài liệu của chúng tôi. Đây là một
liên kết đến "Bản phát hành mới nhất" sẽ đưa bạn đến tài liệu về bản ổn định mới nhất
phát hành ns-3. Nếu bạn chọn liên kết "Tài liệu API", bạn sẽ được đưa đến
ns-3 Trang tài liệu API.

Trong thanh bên, bạn sẽ thấy một hệ thống phân cấp bắt đầu

· Ns-3

· Tài liệu ns-3

· Tất cả các nguồn

· Tất cả các thuộc tính

· Tất cả GlobalValues

Danh sách mà chúng tôi quan tâm ở đây là "Tất cả các nguồn theo dõi". Hãy tiếp tục và chọn liên kết đó.
Bạn sẽ thấy, có lẽ không quá ngạc nhiên, một danh sách tất cả các nguồn theo dõi có sẵn
in ns-3.

Ví dụ: cuộn xuống ns3 :: MobilityModel. Bạn sẽ tìm thấy một mục cho

CourseChange: Giá trị của vectơ vị trí và / hoặc vận tốc đã thay đổi

Bạn nên công nhận đây là nguồn theo dõi chúng tôi đã sử dụng trong thứ ba.cc ví dụ. Đang ngâm
danh sách này sẽ hữu ích.

Config Đường dẫn
Đuợc, I tìm thấy a theo dõi nguồn, làm thế nào do I con số ra các Config con đường đến sử dụng khi nào I kết nối đến
nó?

Nếu bạn biết bạn quan tâm đến đối tượng nào, phần "Mô tả chi tiết" cho
lớp sẽ liệt kê tất cả các nguồn theo dõi có sẵn. Ví dụ: bắt đầu từ danh sách "Tất cả
TraceSources, "nhấp vào ns3 :: MobilityModel liên kết này sẽ đưa bạn đến
tài liệu cho Tính di độngMô hình lớp. Hầu như ở đầu trang là một dòng
mô tả ngắn gọn về lớp học, kết thúc bằng liên kết "Thêm ...". Nhấp vào liên kết này để bỏ qua
tóm tắt API và chuyển đến "Mô tả chi tiết" của lớp. Vào cuối
mô tả sẽ là (tối đa) ba danh sách:

· Config Đường dẫn: danh sách các đường dẫn Cấu hình điển hình cho lớp này.

· Thuộc tính: danh sách tất cả các thuộc tính được cung cấp bởi lớp này.

· nguồn theo dõi: danh sách tất cả các Nguồn Trace có sẵn từ lớp này.

Đầu tiên, chúng ta sẽ thảo luận về các đường dẫn Cấu hình.

Giả sử rằng bạn vừa tìm thấy nguồn theo dõi "CourseChange" trong phần "Tất cả
Danh sách TraceSources "và bạn muốn tìm cách kết nối với nó. Bạn biết rằng bạn đang
sử dụng (một lần nữa, từ thứ ba.cc ví dụ) một ns3 :: RandomWalk2dMobilityModel. Vì vậy
nhấp vào tên lớp trong danh sách "Tất cả nguồn theo dõi" hoặc tìm
ns3 :: RandomWalk2dMobilityModel trong "Danh sách Lớp". Dù bằng cách nào thì bây giờ bạn nên nhìn
tại trang "ns3 :: RandomWalk2dMobilityModel Class Reference".

Nếu bây giờ bạn cuộn xuống phần "Mô tả chi tiết", sau danh sách tóm tắt
các phương thức và thuộc tính của lớp (hoặc chỉ cần nhấp vào liên kết "Thêm ..." ở cuối lớp
mô tả ngắn gọn ở đầu trang) bạn sẽ thấy tài liệu tổng thể về
lớp. Tiếp tục cuộn xuống, tìm danh sách "Đường dẫn cấu hình":
Config Đường dẫn

ns3 :: RandomWalk2dMobilityModel có thể truy cập thông qua các đường dẫn sau với
Cấu hình :: ĐặtCấu hình :: Kết nối:

· "/ NodeList / [i] / $ ns3 :: MobilityModel / $ ns3 :: RandomWalk2dMobilityModel"

Tài liệu cho bạn biết cách truy cập RandomWalk2dMobilityMô hình Vật. Đối chiếu
chuỗi ở trên với chuỗi mà chúng tôi thực sự sử dụng trong mã ví dụ:

"/ NodeList / 7 / $ ns3 :: MobilityModel"

Sự khác biệt là do thực tế là hai Nhận đối tượng các cuộc gọi được ngụ ý trong chuỗi tìm thấy
trong tài liệu. Đầu tiên, cho $ ns3 :: MobilityModel sẽ truy vấn tập hợp cho
lớp cơ sở. Hàm ý thứ hai Nhận đối tượng gọi cho $ ns3 :: RandomWalk2dMobilityModel,
được sử dụng để chuyển lớp cơ sở đến lớp thực thi cụ thể. Các tài liệu
hiển thị cả hai thao tác này cho bạn. Nó chỉ ra rằng nguồn theo dõi thực tế bạn đang
tìm kiếm được tìm thấy trong lớp cơ sở.

Xem thêm trong phần "Mô tả chi tiết" để biết danh sách các nguồn theo dõi.
Bạn sẽ thấy
Không có nguồn nào được xác định cho loại này.

nguồn theo dõi xác định in cha mẹ tốt nghiệp lớp XNUMX `` ns3 :: MobilityModel ''

· Khóa họcThay đổi: Giá trị của vị trí và / hoặc vectơ vận tốc đã thay đổi.

Chữ ký gọi lại: ns3 :: MobilityModel :: CourseChangeCallback

Đây chính là điều bạn cần biết. Nguồn quan tâm theo dõi được tìm thấy trong
ns3 :: MobilityModel (mà bạn đã biết dù sao). Điều thú vị là chút API này
Tài liệu cho bạn biết rằng bạn không cần truyền bổ sung trong đường dẫn cấu hình ở trên để
đến lớp cụ thể, vì nguồn theo dõi thực sự nằm trong lớp cơ sở.
Do đó việc bổ sung Nhận đối tượng không bắt buộc và bạn chỉ cần sử dụng đường dẫn:

"/ NodeList / [i] / $ ns3 :: MobilityModel"

hoàn toàn khớp với đường dẫn ví dụ:

"/ NodeList / 7 / $ ns3 :: MobilityModel"

Ngoài ra, một cách khác để tìm đường dẫn Cấu hình là grep xung quanh ns-3 cơ sở mã
cho một người đã tìm ra nó. Bạn nên luôn cố gắng sao chép của người khác
mã làm việc trước khi bạn bắt đầu viết mã của riêng bạn. Hãy thử một cái gì đó như:

$ tìm thấy. -tên '* .cc' | xargs grep CourseChange | kết nối grep

và bạn có thể tìm thấy câu trả lời của mình cùng với mã làm việc. Ví dụ, trong trường hợp này,
src / Mobile /amples / main-random-topology.cc có một cái gì đó đang chờ bạn sử dụng:

Cấu hình :: Kết nối ("/ NodeList / * / $ ns3 :: MobilityModel / CourseChange",
MakeCallback (& ​​CourseChange));

Chúng tôi sẽ quay lại ví dụ này trong giây lát.

Gọi lại Chữ ký
Đuợc, I tìm thấy a theo dõi nguồn các Config CON ĐƯỜNG làm thế nào do I con số ra các trở lại kiểu
chính thức đối số of my gọi lại chức năng nhu cầu đến được?

Cách dễ nhất là kiểm tra chữ ký gọi lại đánh máy, được đưa ra trong
"Chữ ký gọi lại" của nguồn theo dõi trong "Mô tả chi tiết" cho lớp, như
hiển thị ở trên.

Lặp lại mục nhập nguồn theo dõi "CourseChange" từ ns3 :: RandomWalk2dMobilityModel we
có:

· Khóa họcThay đổi: Giá trị của vị trí và / hoặc vectơ vận tốc đã thay đổi.

Chữ ký gọi lại: ns3 :: MobilityModel :: CourseChangeCallback

Chữ ký gọi lại được đưa ra dưới dạng một liên kết đến đánh máy, nơi chúng tôi tìm thấy
đánh máy làm mất hiệu lực (* CourseChangeCallback) (const std :: string bối cảnh, Ptr
MobilityModel> * người mẫu);

Truy tìmGọi lại chữ ký cho các thông báo thay đổi khóa học.

Nếu cuộc gọi lại được kết nối bằng Kết nốiKhông có Bối cảnh bỏ qua bối cảnh lập luận từ
chữ ký.

Thông số:
[in] context Chuỗi ngữ cảnh do nguồn Trace cung cấp.
[trong] mô hình MobilityModel đang thay đổi hướng đi.

Như trên, để thấy điều này được sử dụng grep xung quanh ns-3 codebase cho một ví dụ. Ví dụ
ở trên, từ src / Mobile /amples / main-random-topology.cc, kết nối "CourseChange"
nguồn theo dõi Khóa họcThay đổi chức năng trong cùng một tệp:

khoảng trống tĩnh
CourseChange (std :: string context, Ptr mô hình)
{
...
}

Lưu ý rằng chức năng này:

· Sử dụng đối số chuỗi "ngữ cảnh", chúng tôi sẽ mô tả trong một phút. (Nếu gọi lại
được kết nối bằng cách sử dụng Kết nốiKhông có Bối cảnh chức năng của bối cảnh đối số sẽ là
bỏ qua.)

· Có Tính di độngMô hình được cung cấp làm đối số cuối cùng (hoặc chỉ đối số nếu
Kết nốiKhông có Bối cảnh Được sử dụng).

· Trả lại làm mất hiệu lực.

Nếu tình cờ, chữ ký gọi lại không được ghi lại và không có ví dụ nào để
làm việc từ đó, xác định đúng chữ ký hàm gọi lại có thể là một thách thức đối với
thực sự tìm ra từ mã nguồn.

Trước khi bắt tay vào hướng dẫn mã, tôi sẽ tử tế và chỉ cho bạn một cách đơn giản
để tìm ra điều này: Giá trị trả về của lệnh gọi lại của bạn sẽ luôn là làm mất hiệu lực. Sự trang trọng
danh sách tham số cho một Truy tìmGọi lại có thể được tìm thấy từ danh sách tham số mẫu trong
tờ khai. Nhớ lại rằng đối với ví dụ hiện tại của chúng ta, đây là mô hình di động.h, nơi chúng tôi
đã tìm thấy trước đây:

TracedCallback > m_courseChangeTrace;

Có sự tương ứng XNUMX-XNUMX giữa danh sách tham số mẫu trong
khai báo và các đối số chính thức của hàm gọi lại. Đây, có một
tham số mẫu, là một Ptr MobilityModel>. Điều này cho bạn biết rằng bạn cần một
hàm trả về giá trị void và nhận một Ptr MobilityModel>. Ví dụ:

làm mất hiệu lực
CourseChange (Ptr người mẫu)
{
...
}

Đó là tất cả những gì bạn cần nếu bạn muốn Cấu hình :: ConnectWithoutContext. Nếu bạn muốn một bối cảnh,
bạn cần Cấu hình :: Kết nối và sử dụng hàm Gọi lại có ngữ cảnh chuỗi, sau đó
các đối số mẫu:

làm mất hiệu lực
CourseChange (const std :: string context, Ptr người mẫu)
{
...
}

Nếu bạn muốn đảm bảo rằng Khóa họcThay đổiGọi lại chức năng chỉ hiển thị trong của bạn
tệp cục bộ, bạn có thể thêm từ khóa tĩnh và nghĩ ra:

khoảng trống tĩnh
CourseChange (const std :: string path, Ptr người mẫu)
{
...
}

đó chính xác là những gì chúng tôi đã sử dụng trong thứ ba.cc thí dụ.

Thực hiện
Phần này là hoàn toàn tùy chọn. Đó sẽ là một chuyến đi gập ghềnh, đặc biệt là đối với những
không quen thuộc với các chi tiết của các mẫu. Tuy nhiên, nếu bạn vượt qua được điều này, bạn sẽ có
một xử lý rất tốt trên rất nhiều ns-3 thành ngữ cấp thấp.

Vì vậy, một lần nữa, hãy tìm ra chữ ký nào của hàm gọi lại là cần thiết cho
Nguồn theo dõi "CourseChange". Điều này sẽ rất đau đớn, nhưng bạn chỉ cần làm điều này
Một lần. Sau khi bạn vượt qua điều này, bạn sẽ có thể chỉ nhìn vào một Truy tìmGọi lại
hiểu nó.

Điều đầu tiên chúng ta cần xem xét là khai báo nguồn gốc. Nhớ lại điều đó
đây là trong mô hình di động.h, nơi chúng tôi đã tìm thấy trước đây:

TracedCallback > m_courseChangeTrace;

Tuyên bố này dành cho một mẫu. Tham số mẫu nằm bên trong dấu ngoặc nhọn,
vì vậy chúng tôi thực sự quan tâm đến việc tìm hiểu những gì TracedCallback <> Là. Nếu bạn có
hoàn toàn không biết thứ này có thể được tìm thấy ở đâu, grep là bạn của bạn.

Chúng tôi có thể sẽ quan tâm đến một số loại khai báo trong ns-3 nguồn, vì vậy
lần đầu tiên thay đổi thành src danh mục. Sau đó, chúng tôi biết tuyên bố này sẽ phải
ở trong một số loại tệp tiêu đề, vì vậy chỉ grep cho nó bằng cách sử dụng:

$ tìm thấy. -tên '* .h' | xargs grep TracedCallback

Bạn sẽ thấy 303 dòng bay qua (Tôi đã tổng hợp thông tin này qua wc để xem nó tệ như thế nào). Mặc dù
điều đó có vẻ như là rất nhiều, đó không thực sự là rất nhiều. Chỉ cần chuyển đầu ra thông qua chi tiết
bắt đầu quét qua nó. Ở trang đầu tiên, bạn sẽ thấy một số rất đáng ngờ
công cụ trông giống như mẫu.

TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::TracedCallback ()
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext (c ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Connect (const CallbackB ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::DisconnectWithoutContext ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Disconnect (const Callba ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (void) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...

Nó chỉ ra rằng tất cả những điều này đến từ tệp tiêu đề truy tìm-callback.h âm thanh nào
rất hứa hẹn. Sau đó, bạn có thể xem qua mô hình di động.h và thấy rằng có một dòng
xác nhận linh cảm này:

#include "ns3 / traced-callback.h"

Tất nhiên, bạn có thể đi từ hướng này từ hướng khác và bắt đầu bằng cách nhìn vào
bao gồm trong mô hình di động.h và nhận thấy sự bao gồm của truy tìm-callback.h
suy ra rằng đây phải là tệp bạn muốn.

Trong cả hai trường hợp, bước tiếp theo là xem xét src / core / model / traced-callback.h in
biên tập viên yêu thích của bạn để xem những gì đang xảy ra.

Bạn sẽ thấy một nhận xét ở đầu tệp đáng an ủi:
Ns3 :: TracedCallback có API gần như giống hệt như một ns3 :: Callback bình thường nhưng
thay vì chuyển tiếp các cuộc gọi đến một hàm duy nhất (như một ns3 :: Callback bình thường),
nó chuyển tiếp các cuộc gọi đến một chuỗi ns3 :: Callback.

Điều này nghe có vẻ rất quen thuộc và cho bạn biết bạn đang đi đúng hướng.

Chỉ sau bình luận này, bạn sẽ tìm thấy

mẫu
typename T3 = trống, typename T4 = trống,
typename T5 = trống, typename T6 = trống,
typename T7 = trống, typename T8 = trống>
lớp TracedCallback
{
...

Điều này cho bạn biết rằng TracedCallback là một lớp mẫu. Nó có tám loại có thể
các tham số với giá trị mặc định. Quay lại và so sánh điều này với tuyên bố của bạn
cố gắng để hiểu:

TracedCallback > m_courseChangeTrace;

Sản phẩm tên loại T1 trong khai báo lớp mẫu tương ứng với Ptr
MobilityModel> trong phần khai báo trên. Tất cả các tham số loại khác được để lại như
các giá trị mặc định. Nhìn vào hàm tạo thực sự không cho bạn biết nhiều điều. Một nơi mà
bạn đã thấy một kết nối được thực hiện giữa chức năng Gọi lại của bạn và hệ thống theo dõi là
trong Kết nốiKết nốiKhông có Bối cảnh chức năng. Nếu bạn cuộn xuống, bạn sẽ thấy một
Kết nốiKhông có Bối cảnh phương pháp ở đây:

mẫu
tên chữ T3, tên chữ T4,
tên chữ T5, tên chữ T6,
typename T7, typename T8>
làm mất hiệu lực
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assign (gọi lại);
m_callbackList.push_back(cb);
}

Bây giờ bạn đang ở trong bụng của con thú. Khi mẫu được khởi tạo cho
khai báo ở trên, trình biên dịch sẽ thay thế T1 với Ptr MobilityModel>.

làm mất hiệu lực
TracedCallback :: ConnectWithoutContext ... cb
{
Gọi lại > cb;
cb.Assign (gọi lại);
m_callbackList.push_back(cb);
}

Bây giờ bạn có thể thấy việc triển khai mọi thứ mà chúng tôi đã đề cập. Mật mã
tạo một Callback đúng loại và gán chức năng của bạn cho nó. Đây là
tương đương với pfi = chức năng của tôi chúng ta đã thảo luận ở đầu phần này. Mật mã
sau đó thêm Callback vào danh sách Callback cho nguồn này. Điều duy nhất còn lại là
để xem định nghĩa của Callback. Sử dụng giống nhau grep lừa như chúng ta đã từng tìm
Truy tìmGọi lại, bạn sẽ có thể tìm thấy rằng tệp ./core/callback.h là một trong những chúng tôi
cần phải nhìn vào.

Nếu bạn nhìn xuống tệp, bạn sẽ thấy rất nhiều điều gần như không thể hiểu được
mã mẫu. Cuối cùng, bạn sẽ đến một số Tài liệu API cho Gọi lại
lớp mẫu, mặc dù. May mắn thay, có một số tiếng Anh:
Gọi lại lớp mẫu.

Mẫu lớp này thực hiện Mẫu thiết kế Functor. Nó được sử dụng để khai báo
loại của một Gọi lại:

· Đối số mẫu không tùy chọn đầu tiên đại diện cho kiểu trả về của lệnh gọi lại.

· Các đối số mẫu kết thúc (tùy chọn) đại diện cho loại
đối số cho lệnh gọi lại.

· Tối đa chín đối số được hỗ trợ.

Chúng tôi đang cố gắng tìm ra những gì

Gọi lại > cb;

khai báo có nghĩa là. Bây giờ chúng tôi hiểu rằng điều đầu tiên (không bắt buộc)
đối số mẫu, làm mất hiệu lực, đại diện cho kiểu trả về của Callback. Thư hai
(tùy chọn) đối số mẫu, Ptr MobilityModel> đại diện cho loại của người đầu tiên
đối số gọi lại.

Callback được đề cập là chức năng của bạn để nhận các sự kiện theo dõi. Từ điều này bạn có thể
suy ra rằng bạn cần một hàm trả về làm mất hiệu lực và mất một Ptr MobilityModel>.
Ví dụ,

làm mất hiệu lực
CourseChangeCallback (Ptr người mẫu)
{
...
}

Đó là tất cả những gì bạn cần nếu bạn muốn Cấu hình :: ConnectWithoutContext. Nếu bạn muốn một bối cảnh,
bạn cần Cấu hình :: Kết nối và sử dụng một hàm Gọi lại có ngữ cảnh chuỗi. Cái này
là bởi vì Kết nối chức năng sẽ cung cấp ngữ cảnh cho bạn. Có thể bạn sẽ cần:

làm mất hiệu lực
CourseChangeCallback (std :: string context, Ptr người mẫu)
{
...
}

Nếu bạn muốn đảm bảo rằng Khóa họcThay đổiGọi lại chỉ hiển thị trong tệp cục bộ của bạn,
bạn có thể thêm từ khóa tĩnh và nghĩ ra:

khoảng trống tĩnh
CourseChangeCallback (std :: string path, Ptr người mẫu)
{
...
}

đó chính xác là những gì chúng tôi đã sử dụng trong thứ ba.cc ví dụ. Có lẽ bây giờ bạn nên quay lại và
đọc lại phần trước (Take My Word for It).

Nếu bạn muốn biết thêm thông tin chi tiết về việc triển khai Callbacks, vui lòng
để nhìn vào ns-3 thủ công. Chúng là một trong những cấu trúc được sử dụng thường xuyên nhất trong
các phần cấp thấp của ns-3. Theo tôi, đó là một điều khá tao nhã.

Giá trị truy tìm
Trước đó trong phần này, chúng tôi đã trình bày một đoạn mã đơn giản sử dụng
TracedValue để chứng minh những điều cơ bản của mã truy tìm. Chúng tôi chỉ đánh bóng qua
TracedValue thực sự là gì và cách tìm kiểu trả về và các đối số chính thức cho
cuộc gọi lại.

Như chúng tôi đã đề cập, tệp, truy tìm giá trị.h mang theo các tờ khai bắt buộc để truy tìm
của 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 chính đối tượng xung quanh, thay vì truyền địa chỉ của đối tượng. Chúng ta mở rộng
yêu cầu đó để bao gồm tập hợp đầy đủ các toán tử kiểu gán
được xác định trước cho các loại dữ liệu cũ thuần túy (POD):

┌───────────────────────────────────
toán tử = (nhiệm vụ) │ │
├───────────────────────────────────
toán tử * =toán tử / =
├───────────────────────────────────
toán tử + =toán tử- =
├───────────────────────────────────
toán tử ++ (cả tiền tố và │ │
│hậu tố) │ │
├───────────────────────────────────
nhà điều hành-- (cả tiền tố và │ │
│hậu tố) │ │
├───────────────────────────────────
toán tử << =toán tử >> =
├───────────────────────────────────
toán tử & =toán tử | =
├───────────────────────────────────
toán tử% =toán tử ^ =
└───────────────────────────────────

Điều này thực sự có nghĩa là bạn sẽ có thể theo dõi tất cả các thay đổi được thực hiện bằng cách sử dụng
toán tử cho một đối tượng C ++ có ngữ nghĩa giá trị.

Sản phẩm TracedValue <> khai báo mà chúng ta đã thấy ở trên cung cấp cơ sở hạ tầng làm quá tải
các toán tử được đề cập ở trên và điều khiển quá trình gọi lại. Sử dụng bất kỳ toán tử nào
ở trên với một Giá trị truy tìm nó sẽ cung cấp cả giá trị cũ và giá trị mới của biến đó,
trong trường hợp này là một int32_t giá trị. Bằng cách kiểm tra Giá trị truy tìm tuyên bố, chúng tôi biết
hàm dấu vết chìm sẽ có đối số (hăng sô int32_t giá trị cũ, const int32_t giá trị mới).
Loại trả lại cho một Giá trị truy tìm hàm gọi lại luôn là làm mất hiệu lực, vì vậy mong đợi
chữ ký gọi lại sẽ là:

void (* TracedValueCallback) (const int32_t oldValue, const int32_t newValue);

Sản phẩm .AddTraceSource trong GetTypeId phương thức cung cấp các "hook" được sử dụng để kết nối
truy xuất nguồn gốc ra thế giới bên ngoài thông qua hệ thống Config. Chúng tôi đã thảo luận về
ba lần đầu tiên để Thêm dấu vết nguồn: tên thuộc tính cho hệ thống cấu hình, trợ giúp
chuỗi và địa chỉ của thành viên dữ liệu lớp TracedValue.

Đối số chuỗi cuối cùng, "ns3 :: Traced :: Value :: Int32" trong ví dụ, là tên của một
đánh máy cho chữ ký hàm gọi lại. Chúng tôi yêu cầu những chữ ký này phải được xác định,
và đặt tên loại đủ điều kiện cho Thêm dấu vết nguồn, vì vậy tài liệu API có thể
liên kết một nguồn theo dõi với chữ ký chức năng. Đối với TracedValue, chữ ký là
thẳng thắn; đối với TracedCallbacks, chúng tôi đã thấy tài liệu API thực sự hữu ích.

Thực Ví dụ
Hãy làm một ví dụ được lấy từ một trong những cuốn sách nổi tiếng nhất về TCP. "TCP / IP
Minh họa, Tập 1: Giao thức, "của W. Richard Stevens là một tác phẩm kinh điển. Tôi vừa lật
cuốn sách mở ra và lướt qua một cốt truyện đẹp về cả cửa sổ tắc nghẽn và trình tự
số so với thời gian ở trang 366. Stevens gọi đây là "Hình 21.10. Giá trị của cwnd và
gửi số thứ tự trong khi dữ liệu đang được truyền. "Hãy tạo lại phần cwnd
của âm mưu đó trong ns-3 sử dụng hệ thống theo dõi và gnuplot.

Có Sẵn nguồn
Điều đầu tiên cần nghĩ đến là chúng ta muốn lấy dữ liệu ra như thế nào. Nó là gì mà chúng tôi
cần truy tìm? Vì vậy, hãy tham khảo danh sách "Tất cả các nguồn theo dõi" để xem chúng tôi phải làm gì
với. Nhớ lại rằng điều này được tìm thấy trong ns-3 Tài liệu API. Nếu bạn cuộn qua
danh sách, cuối cùng bạn sẽ tìm thấy:
ns3 :: TcpNewReno

· Tắc nghẽnCửa sổ: Cửa sổ tắc nghẽn của kết nối TCP

· ChậmBắt ĐầuNgưỡng: Ngưỡng bắt đầu chậm TCP (byte)

Nó chỉ ra rằng ns-3 Việc triển khai TCP tồn tại (hầu hết) trong tệp
src / internet / model / tcp-socket-base.cc trong khi các biến thể kiểm soát tắc nghẽn nằm trong các tệp như
as src / internet / model / tcp-newreno.cc. Nếu bạn không biết điều này a tiên nghiệm, bạn có thể dùng
đệ quy grep bí quyết, Thuật, mẹo:

$ tìm thấy. -tên '* .cc' | xargs grep -i tcp

Bạn sẽ tìm thấy trang này qua trang khác về các trường hợp tcp trỏ bạn đến tệp đó.

Đưa lên tài liệu lớp cho TcpMớiReno và bỏ qua danh sách
TraceSources bạn sẽ tìm thấy
nguồn theo dõi

· Tắc nghẽnCửa sổ: Cửa sổ tắc nghẽn của kết nối TCP

Chữ ký gọi lại: ns3 :: Traced :: Value :: Uint322Callback

Nhấp vào cuộc gọi lại đánh máy liên kết, chúng tôi thấy chữ ký mà bạn biết mong đợi:

void typedef (* ns3 :: Traced :: Value :: Int32Callback) (const int32_t oldValue, const int32_t newValue)

Bây giờ bạn sẽ hiểu mã này hoàn toàn. Nếu chúng ta có một con trỏ đến TcpMớiReno,
chúng ta có thể Dấu vếtKết nối vào nguồn theo dõi "CongestionWindow" nếu chúng tôi cung cấp
mục tiêu gọi lại. Đây là cùng một loại nguồn theo dõi mà chúng ta đã thấy trong ví dụ đơn giản
ở đầu phần này, ngoại trừ việc chúng ta đang nói về uint32_t thay vì
int32_t. Và chúng tôi biết rằng chúng tôi phải cung cấp một hàm gọi lại với chữ ký đó.

Tìm kiếm Các ví dụ
Tốt nhất bạn nên thử và tìm mã làm việc đặt xung quanh mà bạn có thể sửa đổi, thay vì
hơn là bắt đầu từ đầu. Vì vậy, đơn đặt hàng đầu tiên của doanh nghiệp bây giờ là tìm một số mã
đã kết nối nguồn theo dõi "CongestionWindow" và xem liệu chúng tôi có thể sửa đổi nó hay không. Như thường lệ,
grep là bạn của bạn:

$ tìm thấy. -tên '* .cc' | xargs grep CongestionWindow

Điều này sẽ chỉ ra một số ứng cử viên đầy triển vọng: ví dụ / tcp / tcp-large-transfer.cc
src / test / ns3tcp / ns3tcp-cwnd-test-suite.cc.

Chúng tôi chưa truy cập bất kỳ mã thử nghiệm nào, vì vậy hãy xem ở đó. Bạn sẽ
thường thấy rằng mã kiểm tra là khá tối thiểu, vì vậy đây có lẽ là một đặt cược rất tốt.
Mở src / test / ns3tcp / ns3tcp-cwnd-test-suite.cc trong trình soạn thảo yêu thích của bạn và tìm kiếm
"CongestionWindow". Bạn sẽ thấy,

ns3TcpSocket-> TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (& ​​Ns3TcpCwndTestCase1 :: CwndChange, this));

Điều này sẽ trông rất quen thuộc với bạn. Chúng tôi đã đề cập ở trên rằng nếu chúng tôi có một con trỏ đến
TcpMớiReno, chúng ta có thể Dấu vếtKết nối vào nguồn theo dõi "CongestionWindow". Đó là chính xác
những gì chúng tôi có ở đây; vì vậy nó chỉ ra rằng dòng mã này làm chính xác những gì chúng ta muốn.
Hãy tiếp tục và trích xuất mã chúng ta cần từ hàm này (Ns3TcpCwndTestCase1 :: DoRun
(vô hiệu)). Nếu bạn nhìn vào chức năng này, bạn sẽ thấy rằng nó trông giống như một ns-3
kịch bản. Nó chỉ ra đó là chính xác những gì nó là. Nó là một tập lệnh được chạy bởi thử nghiệm
khuôn khổ, vì vậy chúng tôi có thể chỉ cần kéo nó ra và bọc nó vào chính thay vì trong DoRun. Hơn
hơn là đi qua bước này, từng bước, chúng tôi đã cung cấp tệp là kết quả của việc chuyển
bài kiểm tra này trở lại một người bản địa ns-3 kịch bản -- ví dụ / hướng dẫn / thứ năm.cc.

Năng động Dấu vết nguồn
Sản phẩm thứ năm.cc ví dụ minh họa một quy tắc cực kỳ quan trọng mà bạn phải hiểu
trước khi sử dụng bất kỳ loại nguồn theo dõi nào: bạn phải đảm bảo rằng mục tiêu của
Cấu hình :: Kết nối lệnh tồn tại trước khi cố gắng sử dụng nó. Điều này không khác gì nói
một đối tượng phải được khởi tạo trước khi cố gắng gọi nó. Mặc dù điều này có vẻ hiển nhiên
khi được nêu theo cách này, nó sẽ làm tăng nhiều người cố gắng sử dụng hệ thống lần đầu tiên
thời gian.

Hãy quay lại những điều cơ bản trong giây lát. Có ba giai đoạn thực thi cơ bản tồn tại trong
bất kì ns-3 kịch bản. Giai đoạn đầu tiên đôi khi được gọi là "Thời gian cấu hình" hoặc "Thiết lập
Thời gian, "và tồn tại trong khoảng thời gian chính chức năng của tập lệnh của bạn đang chạy, nhưng
trước Trình mô phỏng :: Chạy được gọi là. Giai đoạn thứ hai đôi khi được gọi là "Thời gian mô phỏng"
và tồn tại trong khoảng thời gian khi Trình mô phỏng :: Chạy đang tích cực thực hiện các sự kiện của nó.
Sau khi hoàn thành việc thực thi mô phỏng, Trình mô phỏng :: Chạy sẽ trả lại quyền kiểm soát cho
các chính chức năng. Khi điều này xảy ra, tập lệnh nhập vào thứ có thể được gọi là "Teardown
Giai đoạn, "là khi các cấu trúc và đối tượng được tạo ra trong quá trình thiết lập bị tách rời và
phát hành.

Có lẽ sai lầm phổ biến nhất được thực hiện khi cố gắng sử dụng hệ thống theo dõi là giả định rằng
các thực thể được xây dựng động suốt trong mô phỏng thời gian có sẵn trong quá trình cấu hình
thời gian. Đặc biệt, một ns-3 Ổ cắm là một đối tượng động thường được tạo bởi Ứng dụng đến
giao tiếp giữa Nodes. An ns-3 Các Ứng Dụng luôn có "Thời gian bắt đầu" và "Điểm dừng
Thời gian "gắn liền với nó. Trong phần lớn các trường hợp, một Các Ứng Dụng sẽ không cố gắng
để tạo một đối tượng động cho đến khi Bắt đầuỨng dụng phương thức được gọi ở một số "Bắt đầu
Thời gian ". Điều này nhằm đảm bảo rằng mô phỏng được định cấu hình hoàn chỉnh trước khi ứng dụng
cố gắng làm bất cứ điều gì (điều gì sẽ xảy ra nếu nó cố gắng kết nối với một Node không tồn tại
chưa trong thời gian cấu hình?). Do đó, trong giai đoạn cấu hình, bạn không thể
kết nối nguồn theo dõi với bồn theo dõi nếu một trong số chúng được tạo động trong quá trình
mô phỏng.

Hai giải pháp cho câu hỏi hóc búa này là

1. Tạo một sự kiện giả lập được chạy sau khi đối tượng động được tạo và kết nối
theo dõi khi sự kiện đó được thực thi; hoặc

2. Tạo đối tượng động tại thời điểm cấu hình, sau đó nối nó và đưa đối tượng vào
hệ thống sẽ sử dụng trong thời gian mô phỏng.

Chúng tôi đã thực hiện cách tiếp cận thứ hai trong thứ năm.cc ví dụ. Quyết định này yêu cầu chúng tôi tạo
các Ứng dụng của tôi Các Ứng Dụng, toàn bộ mục đích của việc này là thực hiện một Ổ cắm như một tham số.

Hướng dẫn: thứ năm.cc
Bây giờ, chúng ta hãy xem chương trình ví dụ mà chúng tôi đã xây dựng bằng cách phân tích tắc nghẽn
kiểm tra cửa sổ. Mở ví dụ / hướng dẫn / thứ năm.cc trong trình soạn thảo yêu thích của bạn. Bạn nên thấy
một số mã trông quen thuộc:

/ * - * - Chế độ: C ++; c-file-style: "gnu"; thụt lề-tabs-mode: nil; - * - * /
/*
* Chương trình này là phần mềm miễn phí; bạn có thể phân phối lại nó và / hoặc sửa đổi
* nó theo các điều khoản của Giấy phép Công cộng GNU phiên bản 2 như
* được xuất bản bởi Free Software Foundation;
*
* Chương trình này được phân phối với hy vọng rằng nó sẽ hữu ích,
* nhưng KHÔNG CÓ BẤT KỲ BẢO HÀNH NÀO; mà không có bảo hành ngụ ý
* KHẢ NĂNG LAO ĐỘNG hoặc PHÙ HỢP VỚI MỤC ĐÍCH CỤ THỂ. Xem
* Giấy phép Công cộng GNU để biết thêm chi tiết.
*
* Bạn đáng lẽ đã nhận được một bản sao của Giấy phép Công cộng GNU
* cùng với chương trình này; nếu không, hãy viết thư cho Phần mềm Miễn phí
* Foundation, Bao gồm., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#bao gồm
#include "ns3 / core-module.h"
#include "ns3 / network-module.h"
#include "ns3 / internet-module.h"
#include "ns3 / point-to-point-module.h"
#include "ns3 / apps-module.h"

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

NS_LOG_COMPONENT_DEFINE ("Ví dụ về FifthScript");

Tất cả điều này đã được đề cập, vì vậy chúng tôi sẽ không rehash nó. Các dòng tiếp theo của nguồn là
minh họa mạng và nhận xét giải quyết vấn đề được mô tả ở trên với Ổ cắm.

// ================================================ ===========================
//
// 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 |
// + ---------------- + + ---------------- +
// | |
// + --------------------- +
// 5 Mbps, 2 mili giây
//
//
// Chúng tôi muốn xem xét các thay đổi trong cửa sổ tắc nghẽn TCP ns-3. Chúng tôi cần
// để tạo luồng và nối thuộc tính CongestionWindow trên ổ cắm
// của người gửi. Thông thường, người ta sẽ sử dụng một ứng dụng bật tắt để tạo
// flow, nhưng điều này có một vài vấn đề. Đầu tiên, ổ cắm của on-off
// ứng dụng không được tạo cho đến thời gian Bắt đầu ứng dụng, vì vậy chúng tôi sẽ không
// có thể kết nối socket (hiện tại) tại thời điểm cấu hình. Thứ hai, ngay cả khi chúng ta
// có thể sắp xếp một cuộc gọi sau thời gian bắt đầu, socket không công khai nên chúng tôi
// không hiểu được.
//
// Vì vậy, chúng ta có thể thiết lập một phiên bản đơn giản của ứng dụng bật tắt để thực hiện những gì
// chúng tôi muốn. Về mặt tích cực, chúng tôi không cần tất cả sự phức tạp của tính năng bật-tắt
// ứng dụng. Mặt khác, chúng tôi không có người trợ giúp, vì vậy chúng tôi phải lấy
// tham gia nhiều hơn một chút vào các chi tiết, nhưng điều này là nhỏ.
//
// Vì vậy, trước tiên, chúng ta tạo một ổ cắm và thực hiện kết nối theo dõi trên đó; sau đó chúng tôi vượt qua
// socket này vào phương thức khởi tạo của ứng dụng đơn giản của chúng ta mà sau đó chúng ta
// cài đặt trong nút nguồn.
// ================================================ ===========================
//

Điều này cũng nên tự giải thích.

Phần tiếp theo là phần khai báo của Ứng dụng của tôi Các Ứng Dụng mà chúng tôi kết hợp với nhau để cho phép
các Ổ cắm được tạo tại thời điểm cấu hình.

lớp MyApp: ứng dụng công khai
{
công khai:

Ứng dụng của tôi ();
ảo ~ MyApp ();

void Setup (Ptr socket, Address address, uint32_t packetSize,
uint32_t nPackets, DataRate dataRate);

riêng tư:
ảo void StartApplication (void);
ảo void StopApplication (void);

void ScheduleTx (vô hiệu);
void SendPacket (vô hiệu);

Ptr m_socket;
Địa chỉ m_peer;
uint32_t m_packetSize;
uint32_t m_nGói;
Tốc độ dữ liệu m_dataRate;
Id sự kiện m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};

Bạn có thể thấy rằng lớp này kế thừa từ ns-3 Các Ứng Dụng lớp. Hãy xem
src / network / model / application.h nếu bạn quan tâm đến những gì được kế thừa. Các Ứng dụng của tôi
lớp có nghĩa vụ ghi đè Bắt đầuỨng dụngdừng ứng dụng các phương pháp. Này
các phương thức được tự động gọi khi Ứng dụng của tôi được yêu cầu bắt đầu và ngừng gửi dữ liệu
trong quá trình mô phỏng.

Bắt đầu / Dừng Ứng dụng
Bạn nên dành một chút thời gian giải thích cách các sự kiện thực sự bắt đầu trong
hệ thống. Đây là một lời giải thích khá sâu sắc khác và có thể bị bỏ qua nếu bạn không
lập kế hoạch mạo hiểm đi sâu vào lĩnh vực hoạt động của hệ thống. Nó hữu ích, tuy nhiên, ở chỗ
cuộc thảo luận đề cập đến cách một số phần rất quan trọng của ns-3 làm việc và phơi bày một số
thành ngữ quan trọng. Nếu bạn đang có kế hoạch triển khai các mô hình mới, bạn có thể muốn
hiểu phần này.

Cách phổ biến nhất để bắt đầu các sự kiện bơm là bắt đầu một Các Ứng Dụng. Điều này được thực hiện như
kết quả của các dòng gia đình (hy vọng) sau đây của một ns-3 kịch bản:

Ứng dụng ApplicationContainer = ...
apps.Start (Giây (1.0));
apps.Stop (Giây (10.0));

Mã vùng chứa ứng dụng (xem src / network / helper / application-containerner.h nếu bạn là
quan tâm) lặp qua các ứng dụng và cuộc gọi chứa trong nó,

app-> SetStartTime (startTime);

là kết quả của ứng dụng.Bắt đầu gọi và

app-> SetStopTime (stopTime);

là kết quả của ứng dụng. Dừng lại gọi.

Kết quả cuối cùng của những cuộc gọi này là chúng tôi muốn trình mô phỏng tự động
thực hiện cuộc gọi vào của chúng tôi Ứng dụng để cho họ biết khi nào nên bắt đầu và dừng lại. Trong trường hợp
Ứng dụng của tôi, nó kế thừa từ lớp Các Ứng Dụng và ghi đè Bắt đầuỨng dụng
dừng ứng dụng. Đây là những chức năng sẽ được gọi bởi trình mô phỏng tại
thời điểm thích hợp. Trong trường hợp Ứng dụng của tôi bạn sẽ thấy rằng MyApp :: StartApplication làm
ban đầu Trói buộcKết nối trên socket, sau đó bắt đầu truyền dữ liệu bằng cách gọi
MyApp :: SendPacket. MyApp :: StopApplication ngừng tạo gói bằng cách hủy bất kỳ
sự kiện gửi đang chờ xử lý sau đó đóng ổ cắm.

Một trong những điều tốt đẹp về ns-3 là bạn hoàn toàn có thể bỏ qua việc triển khai
chi tiết về cách của bạn Các Ứng Dụng được trình mô phỏng gọi "tự động" ở đúng
thời gian. Nhưng vì chúng tôi đã mạo hiểm đi sâu vào ns-3 đã, hãy bắt đầu nó.

Nếu bạn nhìn vào src / network / model / application.cc bạn sẽ thấy rằng Đặt thời gian bắt đầu phương pháp
của một Các Ứng Dụng chỉ cần đặt biến thành viên m_startTimeĐặt thời gian dừng phương pháp
chỉ bộ m_stopTime. Từ đó, nếu không có một số gợi ý, con đường mòn có thể sẽ kết thúc.

Chìa khóa để tìm lại đường mòn là biết rằng có một danh sách toàn cầu về tất cả các
các nút trong hệ thống. Bất cứ khi nào bạn tạo một nút trong mô phỏng, một con trỏ đến nút đó
được thêm vào toàn cầu Danh sách nút.

Hãy xem src / network / model / node-list.cc và tìm kiếm NodeList :: Thêm. Công cộng
các cuộc gọi triển khai tĩnh vào một triển khai riêng được gọi là NodeListPriv :: Thêm. Điều này
là một idom tương đối phổ biến trong ns-3. Vì vậy, hãy xem NodeListPriv :: Thêm. Có bạn
sẽ tìm thấy,

Simulator :: ScheduleWithContext (chỉ mục, TimeStep (0), & Node :: Khởi tạo, nút);

Điều này cho bạn biết rằng bất cứ khi nào một Node được tạo trong một mô phỏng, như một hiệu ứng phụ, một lệnh gọi
đến nút đó khởi phương pháp được lập lịch cho bạn sẽ xảy ra ở thời điểm không. Đừng
đọc quá nhiều vào cái tên đó. Nó không có nghĩa là Node sẽ bắt đầu làm
bất cứ điều gì, nó có thể được hiểu là một cuộc gọi cung cấp thông tin vào Node cho nó biết rằng
mô phỏng đã bắt đầu, không phải là một lời kêu gọi hành động yêu cầu Node bắt đầu làm điều gì đó.

Vì vậy, NodeList :: Thêm gián tiếp lên lịch một cuộc gọi đến Nút :: Khởi tạo tại thời điểm không để tư vấn cho một
Node mới mà mô phỏng đã bắt đầu. Nếu bạn nhìn vào src / network / model / node.h bạn
Tuy nhiên, sẽ không tìm thấy một phương pháp được gọi là Nút :: Khởi tạo. Hóa ra là
khởi phương thức được kế thừa từ lớp Đối tượng. Tất cả các đối tượng trong hệ thống có thể
được thông báo khi mô phỏng bắt đầu và các đối tượng của Node lớp chỉ là một loại
các đối tượng.

Hãy xem src / core / model / object.cc tiếp theo và tìm kiếm Đối tượng :: Khởi tạo. Mã này
không đơn giản như bạn có thể mong đợi vì ns-3 Đối tượng hỗ trợ
sự tập hợp. Mã trong Đối tượng :: Khởi tạo sau đó lặp qua tất cả các đối tượng
đã được tổng hợp lại với nhau và gọi là DoKhởi tạo phương pháp. Đây là một thành ngữ khác
điều đó rất phổ biến ở ns-3, đôi khi được gọi là "mẫu thiết kế mẫu".: một công khai
phương thức API không ảo, luôn không đổi qua các lần triển khai và gọi hàm
phương thức triển khai ảo riêng tư được kế thừa và thực hiện bởi các lớp con.
Những cái tên thường giống như Tên phương thức cho API công khai và Tên phương thức cho
API riêng tư.

Điều này cho chúng ta biết rằng chúng ta nên tìm kiếm một Nút :: DoInitialize phương pháp trong
src / network / model / node.cc cho phương pháp sẽ tiếp tục theo dõi của chúng tôi. Nếu bạn xác định vị trí
mã, bạn sẽ tìm thấy một phương thức lặp qua tất cả các thiết bị trong Node và sau đó
tất cả các ứng dụng trong nút gọi thiết bị-> Khởi tạoứng dụng-> Khởi tạo
tương ứng.

Bạn có thể đã biết rằng các lớp học Dụng cụCác Ứng Dụng cả hai đều kế thừa từ lớp Đối tượng
và vì vậy, bước tiếp theo sẽ là xem xét điều gì sẽ xảy ra khi Ứng dụng :: DoInitialize is
gọi là. Hãy xem src / network / model / application.cc và bạn sẽ tìm thấy:

làm mất hiệu lực
Ứng dụng :: DoInitialize (void)
{
m_startEvent = Simulator :: Schedule (m_startTime, & Application :: StartApplication, this);
if (m_stopTime! = TimeStep (0))
{
m_stopEvent = Simulator :: Schedule (m_stopTime, & Application :: StopApplication, this);
}
Đối tượng :: DoInitialize ();
}

Đến đây, cuối cùng chúng ta cũng đi đến cuối con đường mòn. Nếu bạn đã giữ mọi chuyện thẳng thắn, khi bạn
thực hiện một ns-3 Các Ứng Dụng, ứng dụng mới của bạn kế thừa từ lớp Các Ứng Dụng. Bạn
ghi đè lên Bắt đầuỨng dụngdừng ứng dụng phương pháp và cung cấp cơ chế cho
bắt đầu và dừng luồng dữ liệu mới của bạn Các Ứng Dụng. Khi một Node là
được tạo trong mô phỏng, nó được thêm vào một toàn cầu Danh sách nút. Hành động thêm một nút vào
điều này Danh sách nút khiến một sự kiện giả lập được lên lịch cho thời gian bằng XNUMX gọi
Nút :: Khởi tạo phương thức của Node mới được thêm vào sẽ được gọi khi bắt đầu mô phỏng.
Vì một Node kế thừa từ Đối tượng, điều này gọi là Đối tượng :: Khởi tạo phương pháp trên Node
đến lượt nó, gọi là DoKhởi tạo các phương pháp trên tất cả các Đối tượng tổng hợp vào
Nút (nghĩ về mô hình di động). Kể từ nút Đối tượng đã ghi đè DoKhởi tạo, Đó
phương thức được gọi khi bắt đầu mô phỏng. Các Nút :: DoInitialize phương thức gọi
khởi phương pháp của tất cả Ứng dụng trên nút. Từ Ứng dụng cũng là
Đối tượng, điều này gây ra Ứng dụng :: DoInitialize được gọi là. Khi nào
Ứng dụng :: DoInitialize được gọi, nó lên lịch các sự kiện cho Bắt đầuỨng dụng
dừng ứng dụng các cuộc gọi trên Các Ứng Dụng. Các cuộc gọi này được thiết kế để bắt đầu và dừng
luồng dữ liệu từ Các Ứng Dụng

Đây là một hành trình khá dài khác, nhưng nó chỉ phải thực hiện một lần, và bây giờ bạn
hiểu một phần rất sâu sắc khác của ns-3.

Sản phẩm Ứng dụng của tôi Các Ứng Dụng
Sản phẩm Ứng dụng của tôi Các Ứng Dụng tất nhiên cần một hàm tạo và một hàm hủy:

MyApp :: MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nGói (0),
m_dataRate (0),
m_sendEvent(),
m_running (sai),
m_packetsĐã gửi (0)
{
}

MyApp :: ~ MyApp ()
{
m_socket = 0;
}

Sự tồn tại của bit mã tiếp theo là toàn bộ lý do tại sao chúng tôi viết đoạn mã này Các Ứng Dụng in
ngay từ đầu.

làm mất hiệu lực
MyApp :: Thiết lập (Ptr socket, Address address, uint32_t packetSize,
uint32_t nPackets, DataRate dataRate)
{
m_socket = ổ cắm;
m_peer = địa chỉ;
m_packetSize = packSize;
m_nGói = nGói;
m_dataRate = dataRate;
}

Mã này phải khá dễ hiểu. Chúng tôi chỉ đang khởi tạo các biến thành viên.
Điều quan trọng từ quan điểm truy tìm là Ptr ổ cắm mà chúng tôi
cần thiết để cung cấp cho ứng dụng trong thời gian cấu hình. Nhớ lại rằng chúng ta đang đi
để tạo ra Ổ cắm như là một Ổ cắm Tcp (được thực hiện bởi TcpMớiReno) và móc nó
Nguồn theo dõi "CongestionWindow" trước khi chuyển nó tới Thành lập phương pháp.

làm mất hiệu lực
MyApp :: StartApplication (void)
{
m_running = đúng;
m_packetsSent = 0;
m_socket-> Bind ();
m_socket-> Kết nối (m_peer);
Gói gửi ();
}

Đoạn mã trên là phần triển khai được ghi đè Ứng dụng :: StartApplication đó sẽ là
tự động được gọi bởi trình mô phỏng để bắt đầu Các Ứng Dụng chạy ở mức thích hợp
thời gian. Bạn có thể thấy rằng nó làm một Ổ cắm Trói buộc hoạt động. Nếu bạn quen thuộc với
Berkeley Sockets, điều này không có gì đáng ngạc nhiên. Nó thực hiện các công việc cần thiết trên địa phương
bên của kết nối giống như bạn có thể mong đợi. Sau Kết nối sẽ làm những gì là
cần thiết để thiết lập kết nối với TCP tại Địa Chỉ m_peer. Bây giờ nó sẽ rõ ràng
tại sao chúng ta cần trì hoãn nhiều điều này đến thời gian mô phỏng, vì Kết nối sẽ cần
một mạng hoạt động đầy đủ để hoàn thành. Sau Kết nối, Các Các Ứng Dụng sau đó bắt đầu
tạo các sự kiện mô phỏng bằng cách gọi GửiGói.

Đoạn mã tiếp theo giải thích cho Các Ứng Dụng làm thế nào để ngừng tạo các sự kiện mô phỏng.

làm mất hiệu lực
MyApp :: StopApplication (void)
{
m_running = sai;

nếu (m_sendEvent.IsRunning())
{
Trình mô phỏng :: Hủy bỏ (m_sendEvent);
}

nếu (m_socket)
{
m_socket-> Close ();
}
}

Mỗi khi một sự kiện mô phỏng được lên lịch, một Sự kiện được tạo ra. Nếu Sự kiện đang chờ xử lý
thực thi hoặc thực thi, phương pháp của nó Đang chạy sẽ trở lại đúng. Trong mã này, nếu
Đang chạy() trả về true, chúng tôi Hủy bỏ sự kiện xóa nó khỏi sự kiện giả lập
xếp hàng. Bằng cách làm này, chúng tôi phá vỡ chuỗi sự kiện mà Các Ứng Dụng đang sử dụng để giữ
gửi nó GóiCác Ứng Dụng đi yên lặng. Sau khi chúng tôi im lặng Các Ứng Dụng we
Đóng ổ cắm làm hỏng kết nối TCP.

Ổ cắm thực sự bị xóa trong trình hủy khi m_socket = 0 được thực thi. Đây
loại bỏ tham chiếu cuối cùng đến Ptr cơ bản nguyên nhân gây ra trình hủy của
Đối tượng được gọi đó.

Nhớ lại rằng Bắt đầuỨng dụng gọi là GửiGói để bắt đầu chuỗi sự kiện mô tả
các Các Ứng Dụng hành vi.

làm mất hiệu lực
MyApp :: SendPacket (void)
{
Ptr pack = Tạo (m_packetSize);
m_socket-> Gửi (gói tin);

if (++ m_packetsSent <m_nPackets)
{
LịchTx();
}
}

Đây, bạn thấy rằng GửiGói chỉ làm điều đó. Nó tạo ra một Gói và sau đó làm một Gửi
mà, nếu bạn biết Berkeley Sockets, có lẽ chỉ là những gì bạn mong đợi được xem.

Đó là trách nhiệm của Các Ứng Dụng để tiếp tục lên lịch cho chuỗi sự kiện, vì vậy
cuộc gọi dòng tiếp theo lịchTx để lên lịch cho một sự kiện truyền khác (a GửiGói) cho đên khi
Các Ứng Dụng quyết định nó đã gửi đủ.

làm mất hiệu lực
MyApp :: ScheduleTx (void)
{
nếu (m_running)
{
Thời gian tNext (Giây (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator :: Schedule (tNext, & MyApp :: SendPacket, this);
}
}

Đây, bạn thấy rằng lịchTx làm chính xác điều đó. Nếu Các Ứng Dụng đang chạy (nếu
dừng ứng dụng chưa được gọi) nó sẽ lên lịch một sự kiện mới, sự kiện này sẽ gọi GửiGói
lại. Trình đọc cảnh báo sẽ phát hiện ra thứ gì đó cũng thu hút người dùng mới. Tốc độ dữ liệu
của một Các Ứng Dụng chỉ là vậy. Nó không liên quan gì đến tốc độ dữ liệu của một
Kênh. Đây là tỷ lệ mà tại đó Các Ứng Dụng tạo ra các bit. Nó không mất vào
tính toán bất kỳ chi phí nào cho các giao thức hoặc kênh khác nhau mà nó sử dụng để vận chuyển
dữ liệu. Nếu bạn đặt tốc độ dữ liệu của một Các Ứng Dụng với cùng tốc độ dữ liệu như cơ bản của bạn
Kênh cuối cùng bạn sẽ bị tràn bộ đệm.

Dấu vết Bồn rửa
Toàn bộ điểm của bài tập này là nhận các lệnh gọi lại theo dõi từ TCP cho biết
cửa sổ tắc nghẽn đã được cập nhật. Đoạn mã tiếp theo thực hiện
dấu vết chìm:

khoảng trống tĩnh
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator :: Now () .GetSeconds () << "\ t" << newCwnd);
}

Điều này chắc hẳn rất quen thuộc với bạn bây giờ, vì vậy chúng tôi sẽ không đi sâu vào chi tiết. Chức năng này
chỉ cần ghi lại thời gian mô phỏng hiện tại và giá trị mới của cửa sổ tắc nghẽn mỗi
thời gian nó được thay đổi. Bạn có thể tưởng tượng rằng bạn có thể tải kết quả đầu ra
vào một chương trình đồ họa (gnuplot hoặc Excel) và ngay lập tức thấy một biểu đồ đẹp của
hành vi cửa sổ tắc nghẽn theo thời gian.

Chúng tôi đã thêm một dấu vết chìm mới để hiển thị nơi các gói được thả. Chúng tôi sẽ thêm một lỗi
cũng mô hình cho mã này, vì vậy chúng tôi muốn chứng minh điều này hoạt động.

khoảng trống tĩnh
RxDrop (Ptr P)
{
NS_LOG_UNCOND ("RxDrop at" << Simulator :: Now () .GetSeconds ());
}

Dấu vết chìm này sẽ được kết nối với nguồn theo dõi "PhyRxDrop" của điểm-điểm
NetDevice. Nguồn theo dõi này kích hoạt khi một gói bị rơi bởi lớp vật lý của một
thiết bị mạng. Nếu bạn đi một con đường vòng nhỏ đến nguồn
(src / point-to-point / model / point-to-point-net-device.cc) bạn sẽ thấy rằng dấu vết này
nguồn đề cập đến PointToPointNetDevice :: m_phyRxDropTrace. Nếu sau đó bạn nhìn vào
src / point-to-point / model / point-to-point-net-device.h đối với biến thành viên này, bạn sẽ
thấy rằng nó được khai báo là TracedCallback Gói> >. Điều này sẽ cho bạn biết
rằng đích gọi lại phải là một hàm trả về void và nhận một
tham số là một Ptr Gói> (giả sử chúng ta sử dụng Kết nốiKhông có Bối cảnh) -- chỉ
những gì chúng tôi có ở trên.

Chủ yếu chương trình
Đoạn mã sau đây chắc hẳn đã rất quen thuộc với bạn:

int
main (int argc, char * argv [])
{
Các nút NodeContainer;
các nút.Create (2);

PointToPointTrợ giúp pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Độ trễ", StringValue ("2ms"));

Thiết bị NetDeviceContainer;
thiết bị = pointToPoint.Install (các nút);

Điều này tạo ra hai nút có kênh điểm-điểm giữa chúng, giống như được hiển thị trong
hình minh họa ở đầu tệp.

Một vài dòng mã tiếp theo hiển thị một cái gì đó mới. Nếu chúng tôi theo dõi một kết nối hoạt động
một cách hoàn hảo, chúng ta sẽ kết thúc với một cửa sổ tắc nghẽn đơn điệu ngày càng tăng. Để xem bất kỳ
hành vi thú vị, chúng tôi thực sự muốn giới thiệu các lỗi liên kết sẽ làm rơi các gói,
gây ra các ACK trùng lặp và kích hoạt các hành vi thú vị hơn của cửa sổ tắc nghẽn.

ns-3 cung cấp Mô hình lỗi các đối tượng có thể được gắn vào Các kênh. Chúng tôi đang sử dụng
Tỷ lệLỗiMô hình điều này cho phép chúng tôi đưa các lỗi vào một Kênh tại một tỷ lệ.

Ptr em = CreateObject ();
em-> SetAttribute ("ErrorRate", DoubleValue (0.00001));
thiết bị.Get (1) -> SetAttribute ("NhậnErrorModel", PointerValue (em));

Đoạn mã trên khởi tạo một Tỷ lệLỗiMô hình Đối tượng và chúng tôi đặt "ErrorRate" đặc tính
đến giá trị mong muốn. Sau đó, chúng tôi đặt kết quả khởi tạo Tỷ lệLỗiMô hình như lỗi
mô hình được sử dụng bởi point-to-point thiết bị mạng. Điều này sẽ cung cấp cho chúng tôi một số lần truyền lại và
làm cho cốt truyện của chúng tôi thú vị hơn một chút.

Ngăn xếp InternetStackHelper;
stack.Install (các nút);

Địa chỉ Ipv4AddressHelper;
address.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interface = address.Assign (thiết bị);

Đoạn mã trên chắc hẳn đã quen thuộc. Nó cài đặt các ngăn xếp internet trên hai nút của chúng tôi và
tạo giao diện và gán địa chỉ IP cho các thiết bị điểm-điểm.

Vì chúng tôi đang sử dụng TCP, chúng tôi cần một cái gì đó trên Node đích để nhận TCP
kết nối và dữ liệu. Các Gói chìm Các Ứng Dụng thường được sử dụng trong ns-3 cho rằng
mục đích.

uint16_t chìmPort = 8080;
Địa chỉ chìmAddress (InetSocketAddress (giao diện.GetAddress (1), chìmPort));
PacketSinkHelper packSinkHelper ("ns3 :: TcpSocketFactory",
InetSocketAddress (Ipv4Address :: GetAny (), chìmPort));
ApplicationContainer chìmApps = packetSinkHelper.Install (node.Get (1));
chìmApps.Start (Giây (0));
chìmApps.Stop (Giây (20.));

Tất cả điều này nên quen thuộc, ngoại trừ,

PacketSinkHelper packSinkHelper ("ns3 :: TcpSocketFactory",
InetSocketAddress (Ipv4Address :: GetAny (), chìmPort));

Mã này khởi tạo một Gói ChìmNgười Trợ Giúp và yêu cầu nó tạo các socket bằng cách sử dụng lớp
ns3 :: TcpSocketFactory. Lớp này thực hiện một mẫu thiết kế được gọi là "nhà máy đối tượng"
là một cơ chế thường được sử dụng để chỉ định một lớp được sử dụng để tạo các đối tượng trong một
một cách trừu tượng. Tại đây, thay vì phải tự tạo các đối tượng, bạn cung cấp
Gói ChìmNgười Trợ Giúp một chuỗi chỉ định một loạiId chuỗi được sử dụng để tạo một đối tượng
sau đó có thể được sử dụng lần lượt để tạo các phiên bản của Đối tượng do nhà máy tạo ra.

Tham số còn lại cho biết Các Ứng Dụng địa chỉ nào và cổng nó nên Trói buộc đến.

Hai dòng mã tiếp theo sẽ tạo ổ cắm và kết nối nguồn theo dõi.

Ptr ns3TcpSocket = Socket :: CreateSocket (node.Get (0),
TcpSocketFactory :: GetTypeId ());
ns3TcpSocket-> TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (& ​​CwndChange));

Câu lệnh đầu tiên gọi hàm thành viên tĩnh Socket :: CreateSocket và cung cấp một
Nút và một cách rõ ràng loạiId cho nhà máy đối tượng được sử dụng để tạo ổ cắm. Đây là một
cuộc gọi cấp thấp hơn một chút so với Gói ChìmNgười Trợ Giúp gọi ở trên và sử dụng C ++ rõ ràng
nhập thay vì một được tham chiếu bởi một chuỗi. Nếu không, nó giống nhau về mặt khái niệm
Điều.

Một khi các Ổ cắm Tcp được tạo và gắn vào Node, chúng ta có thể sử dụng
TraceConnectWithoutContext để kết nối nguồn theo dõi CongestionWindow với bồn rửa theo dõi của chúng tôi.

Nhớ lại rằng chúng tôi đã mã hóa một Các Ứng Dụng vì vậy chúng tôi có thể lấy nó Ổ cắm chúng tôi vừa thực hiện (trong
thời gian cấu hình) và sử dụng nó trong thời gian mô phỏng. Bây giờ chúng ta phải thực hiện điều đó
Các Ứng Dụng. Chúng tôi đã không gặp bất kỳ khó khăn nào khi tạo một người trợ giúp để quản lý Các Ứng Dụng so
chúng ta sẽ phải tạo và cài đặt nó "theo cách thủ công". Điều này thực sự khá dễ dàng:

Ptr app = CreateObject ();
app-> Setup (ns3TcpSocket, chìmAddress, 1040, 1000, DataRate ("1Mbps"));
node.Get (0) -> AddApplication (ứng dụng);
app-> Start (Giây (1));
app-> Stop (Giây (20.));

Dòng đầu tiên tạo ra một Đối tượng loại Ứng dụng của tôi -- của chúng tôi Các Ứng Dụng. Dòng thứ hai cho biết
các Các Ứng DụngỔ cắm sử dụng, địa chỉ nào để kết nối, lượng dữ liệu cần gửi tại
mỗi sự kiện gửi, số lượng sự kiện gửi để tạo và tốc độ tạo dữ liệu
từ những sự kiện đó.

Tiếp theo, chúng tôi thêm thủ công Ứng dụng của tôi Các Ứng Dụng đến Node nguồn và gọi một cách rõ ràng
Bắt đầuDừng phương pháp trên Các Ứng Dụng để cho nó biết khi nào nên bắt đầu và ngừng làm
Điều.

Chúng tôi thực sự cần thực hiện kết nối từ điểm đến điểm của người nhận thiết bị mạng thả sự kiện
để chúng tôi RxDrop gọi lại ngay bây giờ.

thiết bị.Get (1) -> TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (& ​​RxDrop));

Rõ ràng là bây giờ chúng ta đang nhận được một tham chiếu đến việc nhận Node thiết bị mạng
từ vùng chứa của nó và kết nối nguồn theo dõi được xác định bởi thuộc tính "PhyRxDrop" trên
thiết bị đó vào bồn theo dõi RxDrop.

Cuối cùng, chúng tôi yêu cầu trình mô phỏng ghi đè bất kỳ Ứng dụng và chỉ ngừng xử lý
các sự kiện ở thời điểm 20 giây trong mô phỏng.

Trình mô phỏng :: Dừng (Giây(20));
Trình mô phỏng :: Run ();
Trình mô phỏng :: Phá hủy ();

0 trở về;
}

Nhớ lại điều đó ngay sau khi Trình mô phỏng :: Chạy được gọi, thời gian cấu hình kết thúc và mô phỏng
thời gian bắt đầu. Tất cả công việc mà chúng tôi đã sắp xếp bằng cách tạo ra Các Ứng Dụng và dạy nó
cách kết nối và gửi dữ liệu thực sự xảy ra trong quá trình gọi hàm này.

Ngay khi Trình mô phỏng :: Chạy trả về, mô phỏng hoàn tất và chúng tôi nhập giọt nước
giai đoạn. Trong trường hợp này, Trình mô phỏng :: Phá hủy chăm sóc các chi tiết đẫm máu và chúng tôi chỉ trở lại
mã thành công sau khi hoàn thành.

Chạy thứ năm.cc
Vì chúng tôi đã cung cấp tệp thứ năm.cc cho bạn, nếu bạn đã xây dựng bản phân phối của mình (trong
chế độ gỡ lỗi vì nó sử dụng NS_LOG - nhớ lại rằng các bản dựng được tối ưu hóa sẽ tối ưu hóa NS_LOG) nó
sẽ chờ bạn chạy.

$ ./waf --run thứ năm
Waf: Nhập thư mục `/ home / craigdo / repos / ns-3-allinone-dev / ns-3-dev / build '
Waf: Rời khỏi thư mục `/ home / craigdo / repos / ns-3-allinone-dev / ns-3-dev / build '
'xây dựng' đã hoàn thành thành công (0.684 giây)
1 536
1.0093 1072
1.01528 1608
1.02167 2144
...
1.11319 8040
1.12151 8576
1.12983 9112
RxDrop ở mức 1.13696
...

Bạn có thể thấy ngay mặt trái của việc sử dụng bất kỳ bản in nào trong dấu vết của mình.
Chúng tôi nhận được các thông báo waf không liên quan đó được in trên tất cả các thông tin thú vị của chúng tôi cùng
với các thông báo RxDrop đó. Chúng tôi sẽ sớm khắc phục điều đó, nhưng tôi chắc chắn rằng bạn không thể chờ đợi để xem
kết quả của tất cả công việc này. Hãy chuyển hướng đầu ra đó đến một tệp có tên cwnd.dat:

$ ./waf --run thứ năm> cwnd.dat 2> & 1

Bây giờ hãy chỉnh sửa "cwnd.dat" trong trình chỉnh sửa yêu thích của bạn và xóa trạng thái xây dựng waf và thả
dòng, chỉ để lại dữ liệu được theo dõi (bạn cũng có thể nhận xét
TraceConnectWithoutContext ("PhyRxDrop", gọi lại (& RxDrop)); trong kịch bản để thoát khỏi
của giọt in cũng dễ dàng.

Bây giờ bạn có thể chạy gnuplot (nếu bạn đã cài đặt nó) và yêu cầu nó tạo ra một số
những bức ảnh:

$ gnuplot
gnuplot> đặt thiết bị đầu cuối png kích thước 640,480
gnuplot> đặt đầu ra "cwnd.png"
gnuplot> âm mưu "cwnd.dat" sử dụng tiêu đề 1: 2 'Cửa sổ tắc nghẽn' với các điểm tuyến
gnuplot> thoát

Bây giờ bạn sẽ có một biểu đồ của cửa sổ tắc nghẽn so với thời gian ngồi trong tệp
"cwnd.png" loading = "lazy" trông giống như:
[hình ảnh]

Sử dụng Mức giữa Người giúp việc
Trong phần trước, chúng tôi đã chỉ ra cách tạo nguồn theo dõi và hy vọng
thông tin thú vị từ một mô phỏng. Có lẽ bạn sẽ nhớ lại rằng chúng tôi đã gọi
đăng nhập vào đầu ra tiêu chuẩn bằng cách sử dụng std :: cout một "công cụ cùn" sớm hơn nhiều trong
chương. Chúng tôi cũng đã viết về vấn đề xảy ra như thế nào khi phải phân tích cú pháp đầu ra nhật ký theo thứ tự
để cô lập thông tin thú vị. Bạn có thể nhận ra rằng chúng tôi vừa chi rất nhiều
thời gian triển khai một ví dụ hiển thị tất cả các vấn đề mà chúng tôi muốn khắc phục
các ns-3 hệ thống truy tìm! Bạn sẽ đúng. Nhưng, hãy chịu đựng chúng tôi. Chúng tôi vẫn chưa hoàn thành.

Một trong những điều quan trọng nhất mà chúng tôi muốn làm là có khả năng dễ dàng
kiểm soát lượng đầu ra ra khỏi mô phỏng; và chúng tôi cũng muốn lưu những
dữ liệu vào một tệp để chúng tôi có thể tham khảo lại sau. Chúng tôi có thể sử dụng trình trợ giúp theo dõi cấp trung bình
cung cấp ns-3 để làm điều đó và hoàn thành bức tranh.

Chúng tôi cung cấp một tập lệnh viết các sự kiện thay đổi và thả cwnd được phát triển trong ví dụ
thứ năm.cc vào đĩa trong các tệp riêng biệt. Các thay đổi cwnd được lưu trữ dưới dạng ASCII được phân tách bằng tab
tệp và các sự kiện thả được lưu trữ trong tệp PCAP. Những thay đổi để làm cho điều này xảy ra là
khá nhỏ.

Hướng dẫn: Friday.cc
Chúng ta hãy xem xét những thay đổi cần thiết để bắt đầu từ thứ năm.cc đến Friday.cc. Mở
ví dụ / hướng dẫn / six.cc trong trình soạn thảo yêu thích của bạn. Bạn có thể thấy sự thay đổi đầu tiên bằng cách
tìm kiếm CwndChange. Bạn sẽ thấy rằng chúng tôi đã thay đổi chữ ký cho dấu vết
chìm và đã thêm một dòng vào mỗi phần chìm ghi thông tin đã theo dõi vào
luồng đại diện cho một tệp.

khoảng trống tĩnh
CwndChange (Ptr luồng, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator :: Now () .GetSeconds () << "\ t" << newCwnd);
* stream-> GetStream () << Simulator :: Now () .GetSeconds () << "\ t" << oldCwnd << "\ t" << newCwnd << std :: endl;
}

khoảng trống tĩnh
RxDrop (Ptr tệp, Ptr P)
{
NS_LOG_UNCOND ("RxDrop at" << Simulator :: Now () .GetSeconds ());
file-> Write (Simulator :: Now (), p);
}

Chúng tôi đã thêm thông số "luồng" vào CwndThay đổi dấu vết chìm. Đây là một đối tượng mà
giữ (giữ cho sự tồn tại an toàn) một luồng đầu ra C ++. Nó chỉ ra rằng đây là một rất đơn giản
mà là một đối tượng quản lý các vấn đề lâu dài cho luồng và giải quyết vấn đề thậm chí
người dùng C ++ có kinh nghiệm chạy vào. Nó chỉ ra rằng hàm tạo bản sao cho std :: ostream
được đánh dấu là riêng tư. Điều này có nghĩa rằng std :: ostreams không tuân theo ngữ nghĩa giá trị và không thể
được sử dụng trong bất kỳ cơ chế nào yêu cầu sao chép luồng. Điều này bao gồm ns-3
hệ thống gọi lại, như bạn có thể nhớ lại, yêu cầu các đối tượng tuân theo ngữ nghĩa giá trị.
Lưu ý thêm rằng chúng tôi đã thêm dòng sau trong CwndThay đổi dấu vết chìm
thực hiện:

* stream-> GetStream () << Simulator :: Now () .GetSeconds () << "\ t" << oldCwnd << "\ t" << newCwnd << std :: endl;

Đây sẽ là mã rất quen thuộc nếu bạn thay thế * stream-> GetStream () với std :: cout, Như
trong:

std :: cout << Simulator :: Now () .GetSeconds () << "\ t" << oldCwnd << "\ t" << newCwnd << std :: endl;

Điều này minh họa rằng Ptr thực sự chỉ mang theo một
std :: ofstream cho bạn và bạn có thể sử dụng nó ở đây như bất kỳ luồng đầu ra nào khác.

Một tình huống tương tự xảy ra ở RxDrop ngoại trừ việc đối tượng được truyền xung quanh (a
Ptr) đại diện cho một tệp PCAP. Có một lớp lót trong bồn rửa theo dõi để
ghi dấu thời gian và nội dung của gói được đưa vào tệp PCAP:

file-> Write (Simulator :: Now (), p);

Tất nhiên, nếu chúng ta có các đối tượng đại diện cho hai tệp, chúng ta cần tạo chúng ở đâu đó
và cũng làm cho chúng được chuyển đến các dấu vết chìm. Nếu bạn nhìn vào chính chức năng,
bạn sẽ tìm thấy mã mới để làm điều đó:

AsciiTraceHelper asciiTraceHelper;
Ptr stream = asciiTraceHelper.CreateFileStream ("six.cwnd");
ns3TcpSocket-> TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (& ​​CwndChange, luồng));

...

PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("six.pcap", std :: ios :: out, PcapHelper :: DLT_PPP);
device.Get (1) -> TraceConnectWithoutContext ("PhyRxDrop", MakeBoundCallback (& ​​RxDrop, file));

Trong phần đầu tiên của đoạn mã ở trên, chúng tôi đang tạo tệp theo dõi ASCII,
tạo một đối tượng chịu trách nhiệm quản lý nó và sử dụng một biến thể của lệnh gọi lại
chức năng tạo để sắp xếp cho đối tượng được chuyển đến bồn rửa. Theo dõi ASCII của chúng tôi
trình trợ giúp cung cấp một bộ chức năng phong phú để giúp việc sử dụng tệp văn bản (ASCII) trở nên dễ dàng. Chúng tôi là
chỉ sẽ minh họa việc sử dụng chức năng tạo luồng tệp ở đây.

Sản phẩm TạoTệpLuồng về cơ bản hàm sẽ khởi tạo một std :: ofstream đối tượng và
tạo một tệp mới (hoặc cắt bớt một tệp hiện có). Đây std :: ofstream được đóng gói trong một
ns-3 đối tượng để quản lý trọn đời và giải quyết vấn đề của nhà xây dựng bản sao.

Sau đó chúng tôi lấy cái này ns-3 đối tượng đại diện cho tệp và chuyển nó đến MakeBoundCallback ().
Hàm này tạo ra một cuộc gọi lại giống như MakeCallback (), nhưng nó "liên kết" một giá trị mới với
cuộc gọi lại. Giá trị này được thêm vào làm đối số đầu tiên cho lệnh gọi lại trước khi nó được
gọi là.

Bản chất, MakeBoundCallback (& ​​CwndChange, dòng) khiến nguồn theo dõi thêm
tham số "luồng" bổ sung vào phía trước danh sách tham số chính thức trước khi gọi
cuộc gọi lại. Điều này thay đổi chữ ký bắt buộc của CwndThay đổi chìm để phù hợp với một
được hiển thị ở trên, bao gồm thông số "bổ sung" Ptr dòng.

Trong phần thứ hai của mã trong đoạn mã trên, chúng tôi khởi tạo một Người trợ giúp Pcap làm
điều tương tự đối với tệp theo dõi PCAP của chúng tôi mà chúng tôi đã làm với AsciiTraceTrợ giúp. Dòng của
mã,

Ptr file = pcapHelper.CreateFile ("six.pcap",
"w", PcapHelper :: DLT_PPP);

tạo tệp PCAP có tên "six.pcap" với chế độ tệp "w". Điều này có nghĩa là tệp mới
bị cắt bớt (nội dung bị xóa) nếu tìm thấy tệp hiện có với tên đó. Trận chung kết
tham số là "kiểu liên kết dữ liệu" của tệp PCAP mới. Đây cũng giống như PCAP
các loại liên kết dữ liệu thư viện được xác định trong bpf.h nếu bạn đã quen thuộc với PCAP. Trong trường hợp này,
DLT_PPP cho biết rằng tệp PCAP sẽ chứa các gói có tiền tố là điểm đến
tiêu đề điểm. Điều này đúng vì các gói đến từ thiết bị điểm-điểm của chúng ta
người lái xe. Các loại liên kết dữ liệu phổ biến khác là DLT_EN10MB (10 MB Ethernet) thích hợp cho csma
thiết bị và DLT_IEEE802_11 (IEEE 802.11) thích hợp cho các thiết bị wifi. Chúng được xác định
in src / network / helper / trace-helper.h nếu bạn quan tâm đến việc xem danh sách. Các
các mục trong danh sách khớp với các mục trong bpf.h nhưng chúng tôi sao chép chúng để tránh nguồn PCAP
sự phụ thuộc.

A ns-3 đối tượng đại diện cho tệp PCAP được trả về từ Tạo tập tin và được sử dụng trong một ràng buộc
gọi lại chính xác như trong trường hợp ASCII.

Một đường vòng quan trọng: Điều quan trọng cần lưu ý là mặc dù cả hai đối tượng này đều
được khai báo theo những cách rất giống nhau,

Ptr tập tin ...
Ptr dòng ...

Các đối tượng bên dưới hoàn toàn khác nhau. Ví dụ, Ptr là một
con trỏ thông minh đến một ns-3 Đối tượng là một thứ khá nặng hỗ trợ
Các thuộc tính và được tích hợp vào hệ thống Cấu hình. Các Ptr, Trên
mặt khác, là một con trỏ thông minh đến một đối tượng được đếm tham chiếu, rất nhẹ
Điều. Hãy nhớ nhìn vào đối tượng bạn đang tham chiếu trước khi đưa ra bất kỳ giả định nào
về "quyền hạn" mà đối tượng có thể có.

Ví dụ, hãy xem src / network / utils / pcap-file-wrapper.h trong phân phối và
lưu ý,

class PcapFileWrapper: public Object

lớp đó PcapFileWrapper là một ns-3 Đối tượng bởi tính kế thừa của nó. Sau đó nhìn vào
src / network / model / output-stream-wrapper.h và thông báo,

class OutputStreamWrapper: public
SimpleRefCount

rằng đối tượng này không phải là một ns-3 Đối tượng hoàn toàn, nó "đơn thuần" là một đối tượng C ++ xảy ra với
hỗ trợ đếm tham chiếu xâm nhập.

Vấn đề ở đây là chỉ vì bạn đọc Ptr nó không nhất thiết có nghĩa
việc này một cái gì đó là một ns-3 Đối tượng mà bạn có thể treo ns-3 Các thuộc tính, ví dụ.

Bây giờ, trở lại ví dụ. Nếu bạn xây dựng và chạy ví dụ này,

$ ./waf --run thứ sáu

bạn sẽ thấy các thông báo giống như khi bạn chạy "thứ năm", nhưng hai tệp mới sẽ
xuất hiện trong thư mục cấp cao nhất của ns-3 phân phối.

six.cwnd six.pcap

Vì "six.cwnd" là một tệp văn bản ASCII, bạn có thể xem nó bằng làm sao hoặc tệp yêu thích của bạn
người xem.

1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144
...
9.69256 5149 5204
9.89311 5204 5259

Bạn có một tệp được phân tách bằng tab bằng dấu thời gian, cửa sổ tắc nghẽn cũ và mới
cửa sổ tắc nghẽn phù hợp để nhập trực tiếp vào chương trình cốt truyện của bạn. Không có
các bản in không liên quan trong tệp, không cần phân tích cú pháp hoặc chỉnh sửa.

Vì "six.pcap" là một tệp PCAP, bạn có thể tìm thấy nó bằng tcpdump.

đọc từ tệp six.pcap, PPP kiểu liên kết (PPP)
1.136956 IP 10.1.1.1.49153> 10.1.1.2.8080: Flags [.], Seq 17177: 17681, ack 1, win 32768, options [TS val 1133 ecr 1127, eol], length 504
1.403196 IP 10.1.1.1.49153> 10.1.1.2.8080: Flags [.], Seq 33280: 33784, ack 1, win 32768, options [TS val 1399 ecr 1394, eol], length 504
...
7.426220 IP 10.1.1.1.49153> 10.1.1.2.8080: Flags [.], Seq 785704: 786240, ack 1, win 32768, options [TS val 7423 ecr 7421, eol], length 536
9.630693 IP 10.1.1.1.49153> 10.1.1.2.8080: Flags [.], Seq 882688: 883224, ack 1, win 32768, options [TS val 9620 ecr 9618, eol], length 536

Bạn có một tệp PCAP với các gói đã bị loại bỏ trong mô phỏng. Không có
các gói khác có trong tệp và không có gì khác hiện diện để tạo sự sống
khó khăn.

Đó là một hành trình dài, nhưng giờ chúng ta đã đến thời điểm mà chúng ta có thể đánh giá cao ns-3
hệ thống truy tìm. Chúng tôi đã rút các sự kiện quan trọng ra khỏi giữa quá trình triển khai TCP
và một trình điều khiển thiết bị. Chúng tôi đã lưu trữ những sự kiện đó trực tiếp trong các tệp có thể sử dụng được với
công cụ. Chúng tôi đã làm điều này mà không sửa đổi bất kỳ mã lõi nào có liên quan và chúng tôi đã làm điều này trong
chỉ có 18 dòng mã:

khoảng trống tĩnh
CwndChange (Ptr luồng, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator :: Now () .GetSeconds () << "\ t" << newCwnd);
* stream-> GetStream () << Simulator :: Now () .GetSeconds () << "\ t" << oldCwnd << "\ t" << newCwnd << std :: endl;
}

...

AsciiTraceHelper asciiTraceHelper;
Ptr stream = asciiTraceHelper.CreateFileStream ("six.cwnd");
ns3TcpSocket-> TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (& ​​CwndChange, luồng));

...

khoảng trống tĩnh
RxDrop (Ptr tệp, Ptr P)
{
NS_LOG_UNCOND ("RxDrop at" << Simulator :: Now () .GetSeconds ());
file-> Write (Simulator :: Now (), p);
}

...

PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("six.pcap", "w", PcapHelper :: DLT_PPP);
device.Get (1) -> TraceConnectWithoutContext ("PhyRxDrop", MakeBoundCallback (& ​​RxDrop, file));

Dấu vết Người giúp việc
Sản phẩm 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. Trong các phần trước, chủ yếu
BuildingTopologies, 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 các trình 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: người 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
nên được kích hoạt thông qua một cặp (nút, thiết bị). Ví dụ: bạn có thể muốn chỉ định
rằng theo dõi PCAP nên được kích hoạt trên một thiết bị cụ thể trên một nút cụ thể. Đây
theo sau từ ns-3 mô hình khái niệm thiết bị và cả các mô hình khái niệm của
thiết bị trợ giúp khác nhau. Theo một cách tự nhiên từ điều này, các tệp được tạo 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 khái niệm ngăn xếp giao thức
và cả các mô hình khái niệm của trình trợ giúp ngăn xếp internet. Đương nhiên, dấu vết
các tập tin phải tuân 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 khi nó đượ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.

Dụng cụ Người giúp việc
PCAP
Mục tiêu của những người trợ giúp này là giúp dễ dàng thêm một cơ sở theo dõi PCAP nhất quán vào một
ns-3 thiết bị. Chúng tôi muốn tất cả các hương vị khác nhau của truy tìm PCAP 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
PCAP theo dõi 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.

virtual void EnablePcapInternal (tiền tố std :: string, Ptr nd, bool promiscuous, bool explicitFilename) = 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ả 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.

Phương pháp
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);
void EnablePcap (tiền tố std :: string, NetDeviceContainer d, bool promiscuous = false);
void EnablePcap (tiền tố std :: string, NodeContainer n, bool promiscuous = false);
void EnablePcap (tiền tố std :: string, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
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ỳ
các 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 sử dụng Tài liệu API 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 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 đúng một Node. Ví dụ,

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

· Bạn có thể kích hoạt 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 kể từ khi
thiết bị mạng được đặt tên phải thuộc 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 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à ngầm định vì thiết bị mạng được tìm thấy phải thuộc về
chính xác một nút. 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 tập hợp các cặp nút / thiết bị mạng bằng cách cung cấp
NútContainer. Đối với mỗi nút 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 Node 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ý
trợ giúp), tính năng theo dõi được bật.

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

· Bạn có thể bật theo dõi PCAP trên cơ sở ID Node và ID thiết bị cũng như với
rõ ràng ptr. Mỗi Node trong hệ thống có một số Node ID và mỗi thiết bị được kết nối
đến một Node có ID thiết bị là số nguyên.

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

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

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

Tên tệp
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, PCAP theo dõi trong ns-3 hệ thống có dạng
- id> - id> .pcap

Như đã đề cập trước đó, mọi Node trong hệ thống sẽ có một id Node 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, sau đó, một tệp theo dõi PCAP được tạo ra do cho phép theo dõi lần đầu tiên
thiết bị của Node 21 sử dụng tiền tố "prefix" 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 Node 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 nhận tên này và được
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. Tùy chọn này chỉ có sẵn 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 người trợ giúp thiết bị tạo một PCAP riêng lẻ
nắm bắt 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.

ASCII
Hành vi của trình trợ giúp theo dõi ASCII hỗn hợp về cơ bản tương tự như 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ị phải triển khai
một phương thức ảo được kế thừa từ theo dõi ASCII hỗn hợp.

virtual void EnableAsciiInternal (Ptr dòng,
tiền tố std :: string,
Ptr nd,
bool rõ ràngTên tệp) = 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 theo dõi 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 (tiền tố std :: string, Ptr nd, bool explicitFilename = false);
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 theo dõi ASCII công khai khác sẽ xây dựng dựa trên
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 là gì
người dùng là tất cả những 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.

Phương pháp
void EnableAscii (tiền tố std :: string, Ptr nd, bool explicitFilename = false);
void EnableAscii (Ptr luồng, Ptr nd);

void EnableAscii (tiền tố std :: string, std :: string ndName, bool explicitFilename = false);
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 EnableAsciiAll (tiền tố std :: string);
void EnableAsciiAll (Ptr dòng);

void EnableAscii (tiền tố std :: string, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
void EnableAscii (Ptr luồng, uint32_t nodeid, uint32_t deviceid);

Bạn được khuyến khích sử dụng Tài liệu API cho lớp học AsciiTraceHelperForDevice đến
tìm chi tiết của các phương pháp này; nhưng tóm lại ...

· Có gấp đôi số phương pháp truy tìm ASCII so với PCAP
truy tìm. Điều này là do, ngoài mô hình kiểu PCAP nơi 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.

· Cũng giống như trong theo dõi PCAP, bạn có thể bật theo dõi ASCII trên một (nút, thiết bị mạng) cụ thể
ghép nối 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
vì 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);

· Bốn 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 việc này
hoạt động tương tự với các thông số tương đương trong trường hợp PCAP.

Trong trường hợp này, không có ngữ cảnh theo dõi nào được ghi vào tệp theo dõi 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 theo dõi ASCII trên nhiều thiết bị mạng và gửi tất cả cá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.
Chúng tôi đã thấy điều này trong ví dụ "cwnd" ở trên:

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, theo dõi các ngữ cảnh đang đượ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 hậu tố cho sự nhất quán.

· Bạn có thể bật 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 kể từ khi
thiết bị mạng được đặt tên phải thuộc 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 có tên là `` prefix-client-eth0.tr '' và
`` prefix-server-eth0.tr '' với các dấu vết cho từng thiết bị trong
tệp theo dõi tương ứng. Vì tất cả các chức năng `` EnableAscii ''
quá tải để thực hiện một trình bao bọc luồng, bạn có thể sử dụng biểu mẫu đó như
Tốt::

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ể bật 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à ngầm định vì thiết bị mạng được tìm thấy phải thuộc về
chính xác một nút. Ví dụ,

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

Điều này sẽ dẫn đến một số tệp theo dõi ASCII được tạo,
mỗi trong số đó theo sau dấu `` - - .tr``
quy ước.

Việc kết hợp tất cả các dấu vết thành một tệp duy nhất đượ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ể bật 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. Đối với mỗi nút 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 Node 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ý
trợ giúp), 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 theo dõi ASCII được tạo, mỗi tệp sau
các - id> - id> .tr quy ước. 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ể bật theo dõi PCAP trên cơ sở ID Node và ID thiết bị cũng như với
rõ ràng ptr. Mỗi Node trong hệ thống có một số Node ID và mỗi thiết bị được kết nối
đến một Node có ID thiết bị là số 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ể kích hoạt theo dõi PCAP cho tất cả các thiết bị trong hệ thống, với cùng một loại
như đượ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 theo dõi ASCII được tạo, một tệp cho mọi thiết bị
trong hệ thống của loại được quản lý bởi người trợ giúp. Tất cả các tệp này sẽ tuân theo
- id> - id> .tr quy ước. 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.

Tên tệp
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 theo phương pháp triển khai. Theo quy ước, ASCII theo dấu vết trong ns-3 hệ thống
có dạng - id> - id> .tr

Như đã đề cập trước đó, mọi Node trong hệ thống sẽ có một id Node 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, sau đó, một tệp theo dõi ASCII được tạo do cho phép theo dõi trên
thiết bị của Node 21, sử dụng tiền tố "prefix", 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 Node 21, kết quả
Tên tệp theo dõi 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.

Một số phương thức có tham số mặc định được gọi là tên tệp rõ ràng. Khi đặt thành
true, tham 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 một tên tệp rõ ràng. Tùy chọn này chỉ có sẵn trong các phương pháp có
tiền tố và cho phép theo dõi trên một thiết bị.

Nghị định thư Người giúp việc
PCAP
Mục tiêu của những mixin là giúp dễ dàng thêm cơ sở theo dõi PCAP nhất quán vào
các giao thức. Chúng tôi muốn tất cả các hương vị khác nhau của truy tìm PCAP 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 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ó cùng chữ ký.

virtual void EnablePcapIpv4Internal (tiền tố std :: string,
Ptr ipv4,
giao diện uint32_t,
bool rõ ràngTên tệp) = 0;

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 ipv4, giao diện uint4_t, bool explicitFilename = false);

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 truy tìm PCAP được xây dựng dựa trên việc triển khai này để cung cấp thêm cho 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 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 trong
theo cùng một cách trên các giao thức nếu người trợ giúp triển khai Kích hoạtPcapIpv4Internal đúng.

Phương pháp
Các phương pháp này được thiết kế để tương ứng XNUMX-XNUMX 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ì Node và thiế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 ipv4, giao diện uint4_t, bool explicitFilename = false);
void EnablePcapIpv4 (std :: string prefix, std :: string ipv4Name, uint32_t interface, bool explicitFilename = false);
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, bool explicitFilename);
void EnablePcapIpv4All (tiền tố std :: string);

Bạn được khuyến khích sử dụng Tài liệu API 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ể cho phép 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
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 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 tập hợp các cặp giao thức / giao diện bằng cách cung cấp
Bộ chứa giao diện Ipv4. Cho mỗi IPv4 / giao diện cặp trong vùng chứa giao thức
loại đượ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ình 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ể cho phép 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
NútContainer. Đối với mỗi nút trong NútContainer giao thức thích hợp được tìm thấy.
Đối với mỗi giao thức, các giao diện của nó được liệt kê và theo dõi được bậ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 theo dõi PCAP trên cơ sở Node ID và giao diện. Trong này
trường hợp, id nút được dịch thành 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 kết quả
nguồn truy xuất.

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

· Cuối cùng, bạn có thể kích hoạt theo dõi PCAP cho tất cả các giao diện trong hệ thống, với
giao thứ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ố");

Tên tệp
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 theo phương pháp triển khai. Theo quy ước, dấu vết PCAP được thực hiện cho các thiết bị trong
các ns-3 hệ thống có dạng " - - .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. Điều nà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ó toàn cầu
id giao thức trong hệ thống, chúng tôi sử dụng id Node tương ứng trong việc đặt tên tệp. Vì vậy
có khả năng xảy ra xung đột tên tệp trong các tên tệp theo dõi được chọn tự động.
Vì lý do này, quy ước tên tệp được thay đổi cho các dấu vết giao thức.

Như đã đề cập trước đây, mọi Node trong hệ thống sẽ có id Node do hệ thống gán.
Vì có sự tương ứng XNUMX-XNUMX giữa các phiên bản giao thức và phiên bản Node
chúng tôi sử dụng id Node. Mỗi giao diện có một id giao diện liên quan đến 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 cho phép truy tìm trên
giao diện 1 của giao thức Ipv4 của Node 21 sử dụng tiền tố "prefix" 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 Node
21, tên tệp theo dõi PCAP kết quả sẽ tự động trở thành,
"prefix-nserverIpv4-i1.pcap".

Một số phương thức có tham số mặc định được gọi là tên tệp rõ ràng. Khi đặt thành
true, tham 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 một tên tệp rõ ràng. Tùy chọn này chỉ có sẵn trong các phương pháp có
tiền tố và cho phép theo dõi trên một thiết bị.

ASCII
Hành vi của trình trợ giúp theo dõi ASCII về cơ bản tương tự như trường hợp PCAP. Đi 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
một phương thức ảo được kế thừa từ lớp này.

ảo void EnableAsciiIpv4Internal (Ptr dòng,
tiền tố std :: string,
Ptr ipv4,
giao diện uint32_t,
bool rõ ràngTên tệp) = 0;

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ố std :: string, Ptr ipv4, giao diện uint4_t, bool explicitFilename = false);
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 theo dõi ASCII công khai khác sẽ xây dựng dựa trên
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 là gì
người dùng là tất cả những 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.

Phương pháp
void EnableAsciiIpv4 (tiền tố std :: string, Ptr ipv4, giao diện uint4_t, bool explicitFilename = false);
void EnableAsciiIpv4 (Ptr luồng, Ptr giao diện ipv4, uint4_t);

void EnableAsciiIpv4 (std :: string prefix, std :: string ipv4Name, uint32_t interface, bool explicitFilename = false);
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 EnableAsciiIpv4All (tiền tố std :: string);
void EnableAsciiIpv4All (Ptr dòng);

void EnableAsciiIpv4 (tiền tố std :: string, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
void EnableAsciiIpv4 (Ptr stream, giao diện uint32_t nodeid, uint32_t);

Bạn được khuyến khích sử dụng Tài liệu API cho lớp học PcapAndAsciiHelperForIpv4 đến
tìm chi tiết của các phương pháp này; nhưng tóm lại ...

· Có gấp đôi số phương pháp truy tìm ASCII so với PCAP
truy tìm. Điều này là do, ngoài mô hình kiểu PCAP nơi 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 là
được thay thế bằng cơ chế tham chiếu đến một tệp chung; và số lượng các phương thức API là
nhân đôi để cho phép tất cả các kết hợp.

· Cũng giống như theo dõi PCAP, bạn có thể bật 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 theo dõi 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 thế
của ".pcap".

· Nếu bạn muốn bật theo dõi ASCII trên nhiều giao diện và gửi tất cả cá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.
Chúng tôi đã có một cái gì đó tương tự như điều 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
xác định tên tệp, chuỗi phải bao gồm ", tr" để nhất quán.

· Bạn có thể bật 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 XNUMX-XNUMX giữa các phiên bản giao thức và các 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 gọi là "trace-file-name.tr" chứa tất cả
của các sự kiện theo dõi cho cả hai giao diện. Các sự kiện sẽ được định hướng bằng dấu vết
chuỗi ngữ cảnh.

· Bạn có thể kích hoạt theo dõi ASCII trên tập hợp các cặp giao thức/giao diện bằng cách cung cấp
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 với
được quản lý bởi trình trợ giúp thiết bị), theo dõi được bật cho giao diện tương ứng.
Một lần nữa, ẩn vì có sự tương ứng một đối 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 theo dõi ASCII được tạo, mỗi tệp 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 theo dõi ASCII trên tập hợp các cặp giao thức/giao diện bằng cách cung cấp
NútContainer. Đối với mỗi nút trong NútContainer giao thức thích hợp được tìm thấy.
Đối với mỗi giao thức, các giao diện của nó được liệt kê và theo dõi được bậ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 theo dõi ASCII được tạo, mỗi tệp 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ể bật theo dõi PCAP trên cơ sở ID nút và ID thiết bị. trong này
trường hợp, id nút được dịch thành 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 kết quả
nguồn truy xuất.

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 theo dõi ASCII cho tất cả các giao diện trong hệ thống, với liên kết
giao thứ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 một giao thức thuộc loại do người trợ giúp quản lý. Tất cả
những tập tin này sẽ đi theo -N -tôi
tất cả các dấu vết vào một tệp duy nhất được thực hiện tương tự như các ví dụ trên.

Tên tệp
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 theo phương pháp triển khai. Theo quy ước, ASCII theo dấu vết trong ns-3 hệ thống
có dạng " - - .tr"

Như đã đề cập trước đây, mọi Node trong hệ thống sẽ có id Node 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ố "prefix", 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 và cũng chỉ định giao diện một, tên tệp theo dõi ASCII kết quả sẽ tự động
trở thành, "prefix-nserverIpv4-1.tr".

Một số phương thức có tham số mặc định được gọi là tên tệp rõ ràng. Khi đặt thành
true, tham 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 một tên tệp rõ ràng. Tùy chọn này chỉ có sẵn trong các phương pháp có
tiền tố và cho phép theo dõi trên một thiết bị.

Tổng kết
ns-3 bao gồm một môi trường cực kỳ phong phú cho phép người dùng ở nhiều cấp độ tùy chỉnh
các loại thông tin có thể được trích xuất từ ​​các mô phỏng.

Có các chức năng trợ giúp cấp cao cho phép người dùng kiểm soát đơn giản việc thu thập
đầu ra được xác định trước với độ chi tiết tốt. Có các chức năng trợ giúp cấp trung bình để cho phép
người dùng tinh vi hơn để tùy chỉnh cách trích xuất và lưu thông tin; với chỗ ấy
là các chức năng cốt lõi cấp thấp để cho phép người dùng chuyên gia thay đổi hệ thống để hiển thị các tính năng mới và
thông tin chưa được xuất trước đó theo cách mà người dùng có thể truy cập ngay lập tức tại
cấp độ cao hơn.

Đây là một hệ thống rất toàn diện và chúng tôi nhận ra rằng có rất nhiều thứ để tiêu hóa, đặc biệt là
dành cho người dùng mới hoặc những người không quen thuộc với C++ và các thành ngữ của nó. chúng tôi xem xét
hệ thống theo dõi một phần rất quan trọng của ns-3 và vì vậy khuyên bạn nên trở nên quen thuộc như
có thể với nó. Có lẽ là trường hợp hiểu được phần còn lại của ns-3 hệ thống
sẽ khá đơn giản khi bạn đã thành thạo hệ thống theo dõi

DỮ LIỆU CÁC BỘ SƯU TẬP


Chương hướng dẫn cuối cùng của chúng tôi giới thiệu một số thành phần đã được thêm vào ns-3 trong phiên bản
3.18 và vẫn đang được phát triển. Phần hướng dẫn này cũng là một
công việc đang tiến hành.

Động lực
Một trong những điểm chính của chạy mô phỏng là tạo dữ liệu đầu ra, cho
mục đích nghiên cứu hay đơn giản là để tìm hiểu về hệ thống. Trong chương trước, chúng ta
đã giới thiệu hệ thống con theo dõi và ví dụ Friday.cc. từ đó theo dõi PCAP hoặc ASCII
tập tin được tạo ra. Những dấu vết này có giá trị cho việc phân tích dữ liệu bằng nhiều phương pháp khác nhau.
công cụ bên ngoài và đối với nhiều người dùng, dữ liệu đầu ra như vậy là phương tiện thu thập ưa thích
dữ liệu (để phân tích bằng các công cụ bên ngoài).

Tuy nhiên, cũng có những trường hợp sử dụng không chỉ cho việc tạo tệp theo dõi, bao gồm
Sau đây:

· tạo dữ liệu không ánh xạ tốt tới dấu vết PCAP hoặc ASCII, chẳng hạn như không phải gói
dữ liệu (ví dụ: chuyển đổi máy trạng thái giao thức),

· các mô phỏng lớn mà các yêu cầu I/O của đĩa để tạo các tệp theo dõi là
ngăn cấm hoặc cồng kềnh, và

· nhu cầu về Trực tuyến giảm dữ liệu hoặc tính toán, trong quá trình mô phỏng.
Một ví dụ điển hình về điều này là xác định điều kiện kết thúc cho mô phỏng, để cho biết
nó dừng lại khi nào nó đã nhận đủ dữ liệu để tạo thành một độ tin cậy đủ hẹp
khoảng xung quanh ước tính của một số tham số.

Sản phẩm ns-3 khung thu thập dữ liệu được thiết kế để cung cấp các khả năng bổ sung này
ngoài đầu ra dựa trên dấu vết. Chúng tôi khuyên bạn đọc quan tâm đến chủ đề này nên tham khảo
các ns-3 Hướng dẫn xử lý chi tiết hơn về khung này; ở đây, chúng tôi tóm tắt với
một chương trình ví dụ về một số khả năng đang phát triển.

Ví dụ
ví dụ hướng dẫn ví dụ/hướng dẫn/seventh.cc giống như Friday.cc ví dụ chúng tôi
đã được xem xét trước đó, ngoại trừ một vài thay đổi. Đầu tiên, nó đã được kích hoạt cho IPv6
hỗ trợ với tùy chọn dòng lệnh:

Dòng lệnh cmd;
cmd.AddValue("useIpv6", "UseIpv6", useV6);
cmd.Parse(argc, argv);

Nếu người dùng chỉ định sử dụngIpv6, tùy chọn, chương trình sẽ được chạy bằng IPv6 thay vì IPv4.
Sản phẩm giúp đỡ tùy chọn, có sẵn trên tất cả ns-3 các chương trình hỗ trợ đối tượng CommandLine như
được hiển thị ở trên, có thể được gọi như sau (xin lưu ý việc sử dụng dấu ngoặc kép):

./waf --run "seventh --help"

sản xuất:

ns3-dev-seventh-debug [Đối số chương trình] [Đối số chung]

Đối số chương trình:
--useIpv6: Sử dụng Ipv6 [sai]

Lập luận chung:
--PrintGlobals: In danh sách các hình cầu.
--PrintGroups: In danh sách các nhóm.
--PrintGroup = [group]: In tất cả các TypeIds của nhóm.
--PrintTypeIds: In tất cả các TypeIds.
--PrintAttributes = [typeid]: In tất cả các thuộc tính của typeid.
--PrintHelp: In thông báo trợ giúp này.

Mặc định này (sử dụng IPv4, vì useIpv6 là sai) có thể được thay đổi bằng cách chuyển đổi boolean
giá trị như sau:

./waf --run "seventh --useIpv6=1"

và xem pcap được tạo, chẳng hạn như với tcpdump:

tcpdump -r thứ bảy.pcap -nn -tt

Đây là một sự lạc đề ngắn về hỗ trợ IPv6 và dòng lệnh, cũng
được giới thiệu trước đó trong hướng dẫn này. Đối với một ví dụ chuyên dụng về việc sử dụng dòng lệnh,
vui lòng xem src/core/examples/command-line-example.cc.

Bây giờ trở lại thu thập dữ liệu. bên trong ví dụ/hướng dẫn/ thư mục, gõ như sau
chỉ huy: khác -u Friday.cc thứ bảy.cc, và kiểm tra một số dòng mới của sự khác biệt này:

+ std::string kiểu thăm dò;
+ std::string theo dõiPath;
+ nếu (dùngV6 == sai)
+ {
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+}
+ khác
+ {
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+}
...
+ // Sử dụng GnuplotHelper để vẽ số byte của gói theo thời gian
+ Trình trợ giúp cốt truyện GnuplotHelper;
+
+ // 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ư
+ // đối số lần lượt là tiêu đề cốt truyện, nhãn trục x và trục y
+ plotHelper.ConfigurePlot("đếm-gói-byte-thứ bảy",
+ "Số lượng byte gói so với thời gian",
+ "Thời gian (Giây)",
+ "Số lượng byte gói");
+
+ // Chỉ định loại thăm dò, theo dõi đường dẫn nguồn (trong không gian tên cấu hình) và
+ // thăm dò nguồn theo dõi đầu ra ("OutputBytes") để vẽ đồ thị. Đố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 biểu đồ bằng cách chỉ định vị trí đặt khóa.
+plotHelper.PlotProbe(loại thăm dò,
+ dấu vết,
+ "Bytes đầu ra",
+ "Số lượng byte gói",
+ GnuplotAggregator::KEY_BELOW);
+
+ // Sử dụng FileHelper để ghi số byte của gói theo thời gian
+ Trình trợ giúp tệp Trình trợ giúp tệp;
+
+ // Định cấu hình tệp được ghi và định dạng dữ liệu đầu ra.
+ fileHelper.ConfigureFile("gói-byte-đếm 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\tSố lượng gói byte = %.0f");
+
+ // Chỉ định loại thăm dò, đường dẫn thăm dò (trong không gian tên cấu hình) và
+ // thăm dò nguồn dấu vết đầu ra ("OutputBytes") để ghi.
+ fileHelper.WriteProbe (loại thăm dò,
+ dấu vết,
+ "Bytes đầu ra");
+
Trình mô phỏng :: Dừng (Giây (20));
Trình mô phỏng :: Run ();
Trình mô phỏng :: Phá hủy ();

Người đọc cẩn thận sẽ nhận thấy, khi kiểm tra thuộc tính dòng lệnh IPv6 ở trên,
việc này thứ bảy.cc đã tạo một số tệp đầu ra mới:

thứ bảy-gói-byte-đếm-0.txt
thứ bảy-gói-byte-đếm-1.txt
XNUMXth-pack-byte-count.dat
XNUMXth-pack-byte-count.plt
thứ bảy-gói-byte-đếm.png
XNUMXth-packet-byte-count.sh

Chúng được tạo ra bởi các tuyên bố bổ sung được giới thiệu ở trên; đặc biệt, bởi một
GnuplotHelper và FileHelper. Dữ liệu này được tạo ra bằng cách kết nối bộ sưu tập dữ liệu
thành phần ns-3 nguồn theo dõi và sắp xếp dữ liệu thành một định dạng gnuplot
thành một tệp văn bản được định dạng. Trong các phần tiếp theo, chúng ta sẽ xem xét từng phần này.

Trình trợ giúp Gnuplot
GnuplotHelper là một ns-3 đối tượng trợ giúp nhằm mục đích sản xuất gnuplot âm mưu với
càng ít câu lệnh càng tốt, đối với các trường hợp phổ biến. Nó móc ns-3 theo dõi nguồn với dữ liệu
các loại được hỗ trợ bởi hệ thống thu thập dữ liệu. Không phải tất cả ns-3 các loại dữ liệu nguồn theo dõi là
được hỗ trợ, nhưng nhiều loại theo dõi phổ biến, bao gồm TracedValues ​​với kiểu cũ đơn giản
loại dữ liệu (POD).

Hãy xem đầu ra được tạo bởi trình trợ giúp này:

XNUMXth-pack-byte-count.dat
XNUMXth-pack-byte-count.plt
XNUMXth-packet-byte-count.sh

Đầu tiên là tệp dữ liệu gnuplot với một loạt dấu thời gian và gói được phân tách bằng dấu cách.
số byte. Chúng tôi sẽ đề cập đến cách cấu hình đầu ra dữ liệu cụ thể này bên dưới, nhưng hãy
tiếp tục với các tập tin đầu ra. Tập tin XNUMXth-pack-byte-count.plt là một cốt truyện gnuplot
tệp, có thể được mở từ bên trong gnuplot. Người đọc hiểu cú pháp gnuplot có thể
thấy rằng điều này sẽ tạo ra một tệp PNG đầu ra được định dạng có tên
thứ bảy-gói-byte-đếm.png. Cuối cùng, một shell script nhỏ
XNUMXth-packet-byte-count.sh chạy tệp cốt truyện này thông qua gnuplot để tạo ra mong muốn
PNG (có thể được xem trong trình chỉnh sửa hình ảnh); đó là, lệnh:

sh thứ bảy-gói-byte-count.sh

sẽ mang lại thứ bảy-gói-byte-đếm.png. Tại sao PNG này không được sản xuất trong lần đầu tiên
nơi? Câu trả lời là bằng cách cung cấp tệp plt, người dùng có thể tự cấu hình
kết quả nếu muốn, trước khi tạo PNG.

Tiêu đề hình ảnh PNG cho biết rằng biểu đồ này là biểu đồ của "Số lượng byte gói so với thời gian" và
rằng nó đang vẽ biểu đồ dữ liệu được thăm dò tương ứng với đường dẫn nguồn theo dõi:

/NodeList/*/$ns3::Ipv6L3Protocol/Tx

Lưu ý ký tự đại diện trong đường dẫn theo dõi. Tóm lại, những gì cốt truyện này đang nắm bắt là cốt truyện
số byte gói được quan sát tại nguồn theo dõi truyền của đối tượng Ipv6L3Protocol;
phần lớn các phân đoạn TCP 596 byte theo một hướng và TCP 60 byte tấn công theo hướng khác (hai
nguồn theo dõi nút phù hợp với nguồn theo dõi này).

Làm thế nào điều này đã được cấu hình? Một vài tuyên bố cần phải được cung cấp. Đầu tiên, GnuplotHelper
đối tượng phải được khai báo và cấu hình:

+ // Sử dụng GnuplotHelper để vẽ số byte của gói theo thời gian
+ Trình trợ giúp cốt truyện GnuplotHelper;
+
+ // 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ư
+ // đối số lần lượt là tiêu đề cốt truyện, nhãn trục x và trục y
+ plotHelper.ConfigurePlot("đếm-gói-byte-thứ bảy",
+ "Số lượng byte gói so với thời gian",
+ "Thời gian (Giây)",
+ "Số lượng byte gói");

Đến thời điểm này, một ô trống đã được cấu hình. Tiền tố tên tệp là tiền tố đầu tiên
đối số, tiêu đề cốt truyện là thứ hai, nhãn trục x là thứ ba và nhãn trục y
đối số thứ tư.

Bước tiếp theo là định cấu hình dữ liệu và đây là nơi nối nguồn theo dõi.
Đầu tiên lưu ý ở trên trong chương trình chúng ta đã khai báo một vài biến để sau này sử dụng:

+ std::string kiểu thăm dò;
+ std::string theo dõiPath;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";

Chúng tôi sử dụng chúng ở đây:

+ // Chỉ định loại thăm dò, theo dõi đường dẫn nguồn (trong không gian tên cấu hình) và
+ // thăm dò nguồn theo dõi đầu ra ("OutputBytes") để vẽ đồ thị. Đố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 biểu đồ bằng cách chỉ định vị trí đặt khóa.
+plotHelper.PlotProbe(loại thăm dò,
+ dấu vết,
+ "Bytes đầu ra",
+ "Số lượng byte gói",
+ GnuplotAggregator::KEY_BELOW);

Hai đối số đầu tiên là tên của loại đầu dò và đường dẫn nguồn theo dõi. Này
hai có lẽ là khó xác định nhất khi bạn cố gắng sử dụng khung này để vẽ sơ đồ khác
dấu vết. Dấu vết thăm dò ở đây là Tx nguồn dấu vết của lớp Giao thức Ipv6L3. Khi nào chúng ta
kiểm tra việc thực hiện lớp này (src/internet/model/ipv6-l3-protocol.cc) chúng ta có thể quan sát:

.AddTraceSource("Tx", "Gửi gói IPv6 tới giao diện gửi đi.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))

Điều này nói rằng Tx là một tên cho biến m_txTrace, có tuyên bố là:

/ **
* Gọi lại \brief để theo dõi các gói TX (truyền).
*/
TracedCallback , ptr , uint6_t> m_txTrace;

Hóa ra chữ ký nguồn theo dõi cụ thể này được hỗ trợ bởi một lớp Probe (cái gì
chúng tôi cần ở đây) của lớp Ipv6PacketProbe. xem các tập tin
src/internet/model/ipv6-packet-probe.{h,cc}.

Vì vậy, trong câu lệnh PlotProbe ở trên, chúng ta thấy rằng câu lệnh đang nối dấu vết
nguồn (được xác định bằng chuỗi đường dẫn) với kết quả phù hợp ns-3 loại đầu dò của Đầu dò gói Ipv6. Nếu
chúng tôi không hỗ trợ loại thăm dò này (khớp với chữ ký nguồn theo dõi), chúng tôi không thể
đã sử dụng câu lệnh này (mặc dù một số câu lệnh cấp thấp phức tạp hơn có thể đã được
được sử dụng, như được mô tả trong sách hướng dẫn).

Bản thân Ipv6PacketProbe xuất một số nguồn dấu vết trích xuất dữ liệu ra khỏi
Đối tượng gói thăm dò:

loạiId
Ipv6PacketProbe :: GetTypeId ()
{
static TypeId tid = TypeId ("ns3 :: Ipv6PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ("Đầu ra",
"Gói cộng với đối tượng và giao diện IPv6 của nó đóng vai trò là đầu ra cho đầu dò này",
MakeTraceSourceAccessor (& Ipv6PacketProbe :: m_output))
.AddTraceSource ("OutputBytes",
"Số byte trong gói",
MakeTraceSourceAccessor (& Ipv6PacketProbe :: m_outputBytes))
;
trả lại tid;
}

Đối số thứ ba của câu lệnh PlotProbe của chúng tôi xác định rằng chúng tôi quan tâm đến
số byte trong gói này; cụ thể, nguồn theo dõi "OutputBytes" của
Ipv6PacketProbe. Cuối cùng, hai đối số cuối cùng của tuyên bố cung cấp chú thích cốt truyện
cho chuỗi dữ liệu này ("Số lượng byte gói") và một câu lệnh định dạng gnuplot tùy chọn
(GnuplotAggregator::KEY_BELOW) mà chúng tôi muốn khóa cốt truyện được chèn bên dưới cốt truyện.
Các tùy chọn khác bao gồm NO_KEY, KEY_INSIDE và KEY_ABOVE.

Hỗ trợ Dấu vết Các loại
Các giá trị theo dõi sau đây được hỗ trợ với Probes khi viết bài này:

┌────ệ ───ệ ────hn gái ────────────────────┐
│Loại TracedValue │ Loại đầu dò │ Tệp │
├────ệ ───ệ ────hn gái ────────────────────┤
│double │ DoubleProbe │ stats/model/double-probe.h │
├────ệ ───ệ ────hn gái ────────────────────┤
│uint8_t │ Uinteger8Probe │ stats/model/uinteger-8-probe.h │
├────ệ ───ệ ────hn gái ────────────────────┤
│uint16_t │ Uinteger16Probe │ stats/model/uinteger-16-probe.h │
├────ệ ───ệ ────hn gái ────────────────────┤
│uint32_t │ Uinteger32Probe │ stats/model/uinteger-32-probe.h │
├────ệ ───ệ ────hn gái ────────────────────┤
│bool │ BooleanProbe │ stats/model/uinteger-16-probe.h │
├────ệ ───ệ ────hn gái ────────────────────┤
│ns3::Thời gian │ TimeProbe │ stats/model/time-probe.h │
└────ệ ───ệ ────hn gái ────────────────────┘

Các loại TraceSource sau đây được Probes hỗ trợ khi viết bài này:

┌────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┬─ệ ồ─ ──────────┐
├────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┼─ệ ồ─ ──────────┤
├────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┼─ệ ồ─ ──────────┤
├────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┼─ệ ồ─ ──────────┤
├────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┼─ệ ồ─ ──────────┤
├────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┼─ệ ồ─ ──────────┤
└────ệ ───ệ ────hn gái ───ệ ───ệ ─ ─┴─ệ ồ─ ──────────┘

Như có thể thấy, chỉ có một vài nguồn dấu vết được hỗ trợ và tất cả chúng đều hướng tới
xuất kích thước Gói (tính bằng byte). Tuy nhiên, hầu hết các kiểu dữ liệu cơ bản
có sẵn dưới dạng TracedValues ​​có thể được hỗ trợ với những người trợ giúp này.

Trình trợ giúp tệp
Lớp FileHelper chỉ là một biến thể của ví dụ GnuplotHelper trước đó. Các
chương trình ví dụ cung cấp đầu ra được định dạng của cùng một dữ liệu được đánh dấu thời gian, chẳng hạn như sau:

Thời gian (Giây) = 9.312e + 00 Số byte gói = 596
Thời gian (Giây) = 9.312e + 00 Số byte gói = 564

Hai tệp được cung cấp, một cho nút "0" và một cho nút "1" như có thể thấy trong
tên tập tin. Hãy xem xét từng đoạn mã:

+ // Sử dụng FileHelper để ghi số byte của gói theo thời gian
+ Trình trợ giúp tệp Trình trợ giúp tệp;
+
+ // Định cấu hình tệp được ghi và định dạng dữ liệu đầu ra.
+ fileHelper.ConfigureFile("gói-byte-đếm thứ bảy",
+ FileAggregator::FORMATTED);

Tiền tố tệp của trình trợ giúp tệp là đối số đầu tiên và tiếp theo là một trình xác định định dạng. Một số
các tùy chọn định dạng khác bao gồm SPACE_SEPARATED, COMMA_SEPARATED và TAB_SEPARATED.
Người dùng có thể thay đổi định dạng (nếu FORMATTED được chỉ định) bằng một chuỗi định dạng
chẳng hạn như sau:

+
+ // Đặt nhãn cho tệp đầu ra được định dạng này.
+ fileHelper.Set2dFormat("Thời gian (Giây) = %.3e\tSố lượng gói byte = %.0f");

Cuối cùng, nguồn dấu vết quan tâm phải được móc nối. Một lần nữa, probeType và tracePath
các biến trong ví dụ này được sử dụng và nguồn theo dõi đầu ra của đầu dò "OutputBytes" là
nối:

+
+ // Chỉ định loại thăm dò, theo dõi đường dẫn nguồn (trong không gian tên cấu hình) và
+ // thăm dò nguồn dấu vết đầu ra ("OutputBytes") để ghi.
+ fileHelper.WriteProbe (loại thăm dò,
+ dấu vết,
+ "Bytes đầu ra");
+

Các trường ký tự đại diện trong công cụ xác định nguồn theo dõi này khớp với hai nguồn theo dõi. không giống như
Ví dụ về GnuplotHelper, trong đó hai chuỗi dữ liệu được xếp chồng lên nhau trên cùng một biểu đồ, ở đây, hai
các tệp riêng biệt được ghi vào đĩa.

Tổng kết
Hỗ trợ thu thập dữ liệu mới kể từ ns-3.18 và hỗ trợ cơ bản để cung cấp chuỗi thời gian
đầu ra đã được thêm vào. Mô hình cơ bản được mô tả ở trên có thể được nhân rộng trong
phạm vi hỗ trợ của các đầu dò và nguồn theo dõi hiện có. Nhiều khả năng hơn bao gồm
xử lý số liệu thống kê sẽ được thêm vào trong các bản phát hành trong tương lai.

KẾT LUẬN


Futures
Tài liệu này được dùng như một tài liệu sống. Chúng tôi hy vọng và mong đợi nó sẽ phát triển theo thời gian
để bao gồm ngày càng nhiều các đai ốc và bu lông của ns-3.

Viết các chương hướng dẫn và hướng dẫn không phải là điều mà tất cả chúng ta đều hào hứng, nhưng nó là
rất quan trọng đối với dự án. Nếu bạn là một chuyên gia trong một trong những lĩnh vực này, xin vui lòng
xem xét đóng góp vào ns-3 bằng cách cung cấp một trong những chương này; hoặc bất kỳ chương nào khác mà bạn
có thể nghĩ là quan trọng.

Đóng Cửa
ns-3 là một hệ thống lớn và phức tạp. Không thể bao gồm tất cả những điều bạn
sẽ cần biết trong một hướng dẫn nhỏ. Độc giả muốn tìm hiểu thêm được khuyến khích
đọc các tài liệu bổ sung sau đây:

· Các ns-3 nhãn hiệu

· Các ns-3 tài liệu thư viện mô hình

· Các ns-3 Doxygen (tài liệu API)

· Các ns-3 wiki

-- Các ns-3 nhóm phát triển.

Sử dụng hướng dẫn ns-3 trực tuyến bằng các 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