บทช่วยสอนการจำลองเครือข่าย ns-3 บทที่ 5

บทช่วยสอนการจำลองเครือข่าย ns-3 บทที่ 5
บทที่ 1,2
บทที่ 3
บทที่ 4

5 การตั้งค่า
5.1 การใช้โมดูลการบันทึก
5.1.1 ภาพรวมการบันทึก
5.1.2 เปิดใช้งานการบันทึก
5.1.3 การเพิ่มการบันทึกลงในโค้ดของคุณ
5.2 การใช้อาร์กิวเมนต์บรรทัดคำสั่ง
5.2.1 การแทนที่ค่าแอตทริบิวต์เริ่มต้น
5.2.2 การจับคำสั่งของคุณเอง
5.3 การใช้ระบบติดตาม
5.3.1 การติดตาม ASCII
กำลังแยกวิเคราะห์การติดตาม ASCII
5.3.2 ติดตาม PCAP

5 บท

การตั้งค่า

5.1 การใช้โมดูลการบันทึก

เราได้ดูโมดูลการบันทึก ns-3 คร่าวๆ แล้วโดยดูที่สคริปต์ เฟิร์ส.ซีซี- ในบทนี้ เราจะมาดูการใช้งานที่เป็นไปได้สำหรับระบบย่อยการบันทึกอย่างละเอียดยิ่งขึ้น

5.1.1 ภาพรวมการบันทึก

ระบบขนาดใหญ่จำนวนมากสนับสนุนสิ่งอำนวยความสะดวกในการบันทึกข้อความบางประเภท และ ns-3 ก็ไม่มีข้อยกเว้น ในบางกรณี เฉพาะข้อความแสดงข้อผิดพลาดเท่านั้นที่จะถูกเขียนไปยัง "คอนโซลตัวดำเนินการ" (ซึ่งโดยปกติจะเป็น stderr บนระบบที่ใช้ Unix) บนระบบอื่น ข้อความเตือนอาจแสดงพร้อมทั้งข้อมูลรายละเอียดเพิ่มเติม ในบางกรณี เครื่องมือบันทึกจะถูกใช้เพื่อส่งข้อความการแก้ไขข้อบกพร่องที่สามารถเบลอเอาต์พุตได้อย่างรวดเร็ว

subHRD ที่ใช้ใน ns-3 ถือว่าเนื้อหาข้อมูลระดับเหล่านี้ทั้งหมดมีประโยชน์ และเราจัดเตรียมแนวทางแบบเลือกชั้นเพื่อบันทึกข้อความ การบันทึกสามารถปิดใช้งานได้อย่างสมบูรณ์ เปิดใช้งานตามส่วนประกอบ หรือทั่วโลก เพื่อจุดประสงค์นี้ มีการใช้ระดับเนื้อหาข้อมูลที่ปรับได้ โมดูลการบันทึก ns-3 มอบวิธีการที่ค่อนข้างง่ายในการรับข้อมูลที่เป็นประโยชน์จากการจำลองของคุณ

คุณควรเข้าใจว่าเรามีกลไกสำหรับวัตถุประสงค์ทั่วไป - การติดตาม - สำหรับการดึงข้อมูลจากแบบจำลองของคุณ ซึ่งควรเป็นผลลัพธ์ที่ต้องการสำหรับการจำลอง (สำหรับข้อมูลเพิ่มเติมเกี่ยวกับระบบการติดตามของเรา โปรดดูส่วนบทช่วยสอน 5.3) การบันทึกควรเป็นวิธีที่แนะนำในการรับข้อมูลการดีบัก คำเตือน ข้อความแสดงข้อผิดพลาด หรือสำหรับส่งออกข้อความอย่างรวดเร็วจากสคริปต์หรือโมเดลของคุณได้ตลอดเวลา

ปัจจุบัน ระบบกำหนดระดับ (ประเภท) ของข้อความบันทึกเจ็ดระดับตามลำดับเนื้อหาข้อมูลที่เพิ่มขึ้น

  • LOG_ERROR - ข้อความแสดงข้อผิดพลาดในการบันทึก (มาโครที่เกี่ยวข้อง: NS_LOG_ERROR)
  • LOG_WARN - บันทึกข้อความเตือน (มาโครที่เกี่ยวข้อง: NS_LOG_WARN);
  • LOG_DEBUG - บันทึกข้อความดีบักพิเศษที่ค่อนข้างหายาก (มาโครที่เกี่ยวข้อง: NS_LOG_DEBUG)
  • LOG_INFO - การลงทะเบียนข้อความข้อมูลเกี่ยวกับความคืบหน้าของโปรแกรม (มาโครที่เกี่ยวข้อง: NS_LOG_INFO)
  • LOG_FUNCTION - บันทึกข้อความที่อธิบายแต่ละฟังก์ชันที่ถูกเรียกใช้ (มาโครที่เกี่ยวข้องสองตัว: NS_LOG_FUNCTION ใช้สำหรับฟังก์ชันสมาชิก และ NS_LOG_FUNCTION_NOARGS ใช้สำหรับฟังก์ชันคงที่)
  • LOG_LOGIC - ข้อความบันทึกที่อธิบายโฟลว์ลอจิคัลภายในฟังก์ชัน (มาโครที่เกี่ยวข้อง: NS_LOG_LOGIC)
  • LOG_ALL - บันทึกทุกสิ่งที่กล่าวถึงข้างต้น (ไม่มีมาโครที่เกี่ยวข้อง)
    สำหรับแต่ละประเภท (LOG_TYPE) ยังมี LOG_LEVEL_TYPE ซึ่งหากใช้ จะอนุญาตให้ทุกระดับที่อยู่เหนือระดับนั้นถูกบันทึก นอกเหนือจากระดับของมันเอง (ด้วยเหตุนี้ LOG_ERROR และ LOG_LEVEL_ERROR และ LOG_ALL และ LOG_LEVEL_ALL จึงเทียบเท่ากับฟังก์ชันการทำงาน) ตัวอย่างเช่น การเปิดใช้งาน LOG_INFO จะอนุญาตเฉพาะข้อความที่มาจากมาโคร NS_LOG_INFO เท่านั้น ในขณะที่การเปิดใช้งาน LOG_LEVEL_INFO จะรวมข้อความที่มาจากมาโคร NS_LOG_DEBUG, NS_LOG_WARN และ NS_LOG_ERROR ด้วย

นอกจากนี้เรายังมีมาโครการบันทึกแบบไม่มีเงื่อนไขซึ่งจะแสดงอยู่เสมอ โดยไม่คำนึงถึงระดับการบันทึกหรือองค์ประกอบการเลือก

  • NS_LOG_UNCOND - การบันทึกข้อความที่เกี่ยวข้องโดยไม่มีเงื่อนไข (ไม่มีระดับการบันทึกที่เกี่ยวข้อง)

แต่ละระดับสามารถสอบถามเป็นรายบุคคลหรือสะสมได้ การบันทึกสามารถกำหนดค่าได้โดยใช้ตัวแปรสภาพแวดล้อม sh NS_LOG หรือโดยการบันทึกการเรียกฟังก์ชันของระบบ ดังที่แสดงไว้ก่อนหน้านี้ ระบบบันทึกข้อมูลมีเอกสาร Doxygen และตอนนี้เป็นเวลาที่ดีที่จะตรวจสอบเอกสารดังกล่าว หากคุณยังไม่ได้ตรวจสอบ

ตอนนี้คุณได้อ่านเอกสารอย่างละเอียดแล้ว ลองใช้ความรู้นั้นเพื่อรับข้อมูลที่น่าสนใจจากสคริปต์ตัวอย่างกัน scratch/myfirst.ccที่คุณได้รวบรวมไว้แล้ว

5.1.2 เปิดใช้งานการบันทึก

ลองใช้ตัวแปรสภาพแวดล้อม NS_LOG เพื่อรันบันทึกเพิ่มเติม แต่ก่อนอื่น เพียงเพื่อให้ได้ทิศทางของคุณ ให้รันสคริปต์สุดท้ายเหมือนที่คุณทำก่อนหน้านี้

$ ./waf --run scratch/myfirst

คุณควรเห็นผลลัพธ์ที่คุ้นเคยจากโปรแกรมตัวอย่าง ns-3 แรก

$ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' 'build'
finished successfully (0.413s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

ปรากฎว่าข้อความ "ส่ง" และ "ได้รับ" ที่คุณเห็นด้านบนเป็นข้อความที่บันทึกไว้จริงๆ UdpEchoClientApplication и UdpEchoServerApplication- ตัวอย่างเช่น เราสามารถขอให้แอปพลิเคชันไคลเอนต์พิมพ์ข้อมูลเพิ่มเติมโดยการตั้งค่าระดับการบันทึกผ่านตัวแปรสภาพแวดล้อม NS_LOG

จากนี้ไป ฉันจะถือว่าคุณกำลังใช้เชลล์ที่มีลักษณะคล้าย sh ที่ใช้ไวยากรณ์ "VARIABLE=value" หากคุณใช้เชลล์ที่มีลักษณะคล้าย csh คุณจะต้องแปลงตัวอย่างของฉันเป็นรูปแบบ "ค่าตัวแปร setenv" ที่เชลล์เหล่านั้นต้องการ

ปัจจุบันแอปพลิเคชันไคลเอ็นต์ UDP echo ตอบสนองต่อบรรทัดโค้ดต่อไปนี้ scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

เปิดใช้งานระดับการบันทึก LOG_LEVEL_INFO เมื่อเราผ่านแฟล็กระดับการบันทึก เราจะเปิดใช้งานระดับนั้นและระดับที่ต่ำกว่าทั้งหมดจริงๆ ในกรณีนี้ เราได้เปิดใช้งาน NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN และ NS_LOG_ERROR แล้ว เราสามารถเพิ่มระดับการบันทึกและรับข้อมูลเพิ่มเติม โดยไม่ต้องเปลี่ยนสคริปต์และการคอมไพล์ใหม่ โดยการตั้งค่าตัวแปรสภาพแวดล้อม NS_LOG ดังนี้:

$ export NS_LOG=UdpEchoClientApplication=level_all

ดังนั้นเราจึงตั้งค่าตัวแปร sh เชลล์ NS_LOG เป็นค่าต่อไปนี้

UdpEchoClientApplication=level_all

ด้านซ้ายของงานคือชื่อของส่วนประกอบที่บันทึกไว้ที่เราต้องการกำหนดค่า และด้านขวาคือแฟล็กที่เราต้องการนำไปใช้ ในกรณีนี้ เราจะเปิดใช้งานการดีบักทุกระดับในแอปพลิเคชัน หากคุณรันสคริปต์โดยตั้งค่า NS_LOG ด้วยวิธีนี้ ระบบการบันทึก ns-3 จะยอมรับการเปลี่ยนแปลง และคุณควรเห็นผลลัพธ์ต่อไปนี้:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

ข้อมูลการดีบักเพิ่มเติมที่แอปพลิเคชันมอบให้ขณะนี้อยู่ที่ระดับ NS_LOG_FUNCTION มันแสดงให้เห็นทุกกรณีของการเรียกใช้ฟังก์ชันระหว่างการเรียกใช้สคริปต์ ตามกฎทั่วไป ควรใช้ฟังก์ชันเมธอด (อย่างน้อยที่สุด)NS_LOG_FUNCTION (this)... ใช้ NS_LOG_FUNCTION_NOARGS ()
เฉพาะในฟังก์ชันคงที่เท่านั้น อย่างไรก็ตาม โปรดทราบว่าระบบ ns-3 ไม่จำเป็นต้องมีเพื่อรองรับฟังก์ชันการบันทึกใดๆ การตัดสินใจเกี่ยวกับจำนวนข้อมูลที่ถูกบันทึกไว้จะเป็นของผู้พัฒนาโมเดลแต่ละคน ในกรณีของแอปพลิเคชัน echo มีเอาต์พุตการบันทึกจำนวนมาก

ตอนนี้คุณสามารถดูบันทึกการเรียกใช้ฟังก์ชันที่แอปพลิเคชันสร้างขึ้นได้ หากมองใกล้ ๆ จะสังเกตเห็นเครื่องหมายโคลอนอยู่ระหว่างเส้น UdpEchoClientApplication และชื่อของวิธีการ ซึ่งคุณอาจคาดหวังว่าจะเห็นตัวดำเนินการขอบเขต C++ (: :) นี่เป็นการจงใจ

นี่ไม่ใช่ชื่อของคลาสจริงๆ แต่เป็นชื่อของส่วนประกอบการบันทึก เมื่อมีการจับคู่กันระหว่างซอร์สไฟล์และคลาส โดยปกติจะเป็นชื่อของคลาส แต่คุณควรตระหนักว่าจริงๆ แล้วมันไม่ใช่ชื่อของคลาส และมีโคลอนเดียวแทนที่จะเป็นโคลอนคู่ นี่เป็นวิธีที่จะช่วยคุณแยกแนวคิดชื่อ logging bean ออกจากชื่อคลาสด้วยวิธีที่ค่อนข้างละเอียดอ่อน

อย่างไรก็ตาม ในบางกรณี อาจเป็นเรื่องยากในการพิจารณาว่าวิธีใดที่สร้างข้อความบันทึกจริง หากดูข้อความด้านบนแล้วอาจสงสัยว่าบรรทัดไหน "Received 1024 bytes from 10.1.1.2- คุณสามารถแก้ไขปัญหานี้ได้โดยการตั้งค่าระดับ คำนำหน้า_func ไปยังตัวแปรสภาพแวดล้อม NS_LOG ลองดังต่อไปนี้:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

โปรดทราบว่าจำเป็นต้องใช้เครื่องหมายคำพูดเนื่องจากแถบแนวตั้งที่เราใช้เพื่อแสดงการดำเนินการ OR นั้นเป็นตัวเชื่อมต่อไปป์ Unix เช่นกัน ตอนนี้ หากคุณเรียกใช้สคริปต์ คุณจะเห็นว่าระบบการบันทึกช่วยให้แน่ใจว่าทุกข้อความในบันทึกที่กำหนดขึ้นต้นด้วยชื่อส่วนประกอบ

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

ตอนนี้คุณสามารถเห็นได้ว่าข้อความทั้งหมดที่มาจากแอปพลิเคชันไคลเอ็นต์ UDP echo ได้รับการระบุเช่นนั้น ข้อความ "Received 1024 bytes from 10.1.1.2" ได้รับการระบุอย่างชัดเจนว่ามาจากแอปพลิเคชันไคลเอนต์ echo ข้อความที่เหลือต้องมาจากแอปพลิเคชันเซิร์ฟเวอร์ UDP echo เราสามารถเปิดใช้งานส่วนประกอบนี้ได้โดยการป้อนรายการส่วนประกอบที่คั่นด้วยโคลอนในตัวแปรสภาพแวดล้อม NS_LOG

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

คำเตือน: ในข้อความตัวอย่างด้านบน คุณจะต้องลบอักขระขึ้นบรรทัดใหม่หลังเครื่องหมายทวิภาค (:) ซึ่งใช้ในการจัดรูปแบบเอกสาร ตอนนี้ ถ้าคุณรันสคริปต์ คุณจะเห็นข้อความบันทึกทั้งหมดจากแอปพลิเคชัน echo ไคลเอนต์และเซิร์ฟเวอร์ คุณจะเห็นว่าสิ่งนี้มีประโยชน์มากเมื่อทำการดีบัก

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
UdpEchoServerApplication:HandleRead(): Echoing packet
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

บางครั้งการดูเวลาจำลองที่สร้างข้อความบันทึกก็มีประโยชน์เช่นกัน คุณสามารถทำได้โดยการเพิ่ม OR บิต คำนำหน้า_เวลา:

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

คุณจะต้องลบอักขระขึ้นบรรทัดใหม่ด้านบนออกอีกครั้ง หากคุณรันสคริปต์ตอนนี้ คุณจะเห็นผลลัพธ์ต่อไปนี้:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

โปรดทราบว่าตัวสร้างสำหรับ UdpEchoServer ถูกเรียกระหว่างการจำลอง 0 วินาที สิ่งนี้เกิดขึ้นจริงก่อนที่การจำลองจะเริ่มขึ้น แต่เวลาจะแสดงเป็นศูนย์วินาที เช่นเดียวกับข้อความตัวสร้าง UdpEchoClient.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

จำได้ว่าสคริปท์. scratch/first.cc เริ่มต้นแอปพลิเคชันเซิร์ฟเวอร์ echo หนึ่งวินาทีก่อนเริ่มการจำลอง ตอนนี้คุณจะเห็นแล้วว่าวิธีการ เริ่มแอปพลิเคชัน เซิร์ฟเวอร์ถูกเรียกจริง ๆ ในวินาทีแรก คุณอาจสังเกตเห็นว่าไคลเอนต์ echo เริ่มต้นในวินาทีที่สองของการจำลอง ตามที่เราถามในสคริปต์

ตอนนี้คุณสามารถติดตามความคืบหน้าของการจำลองได้ทางโทรศัพท์ กำหนดการส่ง ในไคลเอนต์ที่เรียกการเรียกกลับ HandleRead ส่งในแอปพลิเคชันเซิร์ฟเวอร์ echo โปรดทราบว่าเวลาที่ผ่านไปในการส่งแพ็คเก็ตผ่านลิงก์แบบจุดต่อจุดคือ 3,69 มิลลิวินาที คุณจะเห็นว่าเซิร์ฟเวอร์ echo บันทึกข้อความที่ตอบกลับแพ็กเก็ต จากนั้น หลังจากการหน่วงเวลาของช่องสัญญาณ คุณจะเห็นว่าไคลเอนต์ echo ได้รับแพ็กเก็ต echo ในวิธี HandleRead

ในการจำลองนี้ มีสิ่งต่างๆ มากมายเกิดขึ้นโดยที่คุณไม่สังเกตเห็น แต่คุณสามารถติดตามกระบวนการทั้งหมดได้อย่างง่ายดายโดยเปิดใช้งานส่วนประกอบการบันทึกทั้งหมดในระบบ ลองตั้งค่าตัวแปร NS_LOG เป็นค่าต่อไปนี้

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

เครื่องหมายดอกจันด้านบนเป็นอักขระไวด์การ์ดสำหรับส่วนประกอบการบันทึก ซึ่งจะรวมรายการทั้งหมดในส่วนประกอบทั้งหมดที่ใช้ในการจำลอง ฉันจะไม่สร้างเอาต์พุตซ้ำที่นี่ (ในขณะที่เขียนมันจะสร้างเอาต์พุต 1265 บรรทัดสำหรับแพ็กเก็ต echo เดียว) แต่คุณสามารถเปลี่ยนเส้นทางข้อมูลนี้ไปยังไฟล์และดูในโปรแกรมแก้ไขที่คุณชื่นชอบได้

$ ./waf --run scratch/myfirst > log.out 2>&1

โดยส่วนตัวแล้วฉันใช้การบันทึกเวอร์ชันที่ละเอียดมากนี้เมื่อฉันมีปัญหาและไม่รู้ว่ามีอะไรผิดพลาดตรงไหน ฉันสามารถติดตามการเรียกใช้โค้ดได้อย่างง่ายดายโดยไม่ต้องตั้งค่าเบรกพอยต์และก้าวผ่านโค้ดในดีบักเกอร์ ฉันสามารถแก้ไขผลลัพธ์ในโปรแกรมแก้ไขที่ฉันชื่นชอบและมองหาสิ่งที่ฉันคาดหวังและเห็นบางสิ่งเกิดขึ้นโดยที่ฉันไม่คาดคิด เมื่อฉันมีความคิดทั่วไปเกี่ยวกับสิ่งที่ผิดพลาด ฉันจะกระโดดเข้าสู่โปรแกรมดีบักเกอร์เพื่อเจาะลึกปัญหา เอาต์พุตประเภทนี้มีประโยชน์อย่างยิ่งเมื่อสคริปต์ของคุณทำสิ่งที่ไม่คาดคิดโดยสิ้นเชิง หากคุณใช้เฉพาะดีบักเกอร์ คุณอาจพลาดการเปลี่ยนแปลงไปอย่างสิ้นเชิง การลงทะเบียนทำให้การเลี้ยวดังกล่าวเห็นได้ชัดเจน

5.1.3 การเพิ่มการบันทึกลงในโค้ดของคุณ

คุณสามารถเพิ่มรายการใหม่ให้กับการจำลองของคุณได้โดยการเรียกส่วนประกอบบันทึกจากมาโครหลายตัว มาทำในสคริปต์กัน myfirst.ccซึ่งเรามีอยู่ในไดเรกทอรี "สะอาด" โปรดจำไว้ว่าเราได้กำหนดองค์ประกอบการบันทึกในสถานการณ์นี้:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

คุณทราบว่าคุณสามารถเปิดใช้งานการบันทึกข้อความทั้งหมดจากส่วนประกอบนี้ได้โดยการตั้งค่าตัวแปรสภาพแวดล้อม NS_LOG ในระดับที่แตกต่างกัน ไปข้างหน้าและเพิ่มรายการลงในสคริปต์ แมโครที่ใช้ในการเพิ่มข้อความระดับข้อมูลลงในบันทึกคือ NS_LOG_INFO มาเพิ่มข้อความ (ก่อนที่เราจะเริ่มสร้างโหนด) ที่บอกคุณว่าสคริปต์อยู่ในขั้นตอน "การสร้างโทโพโลยี" ซึ่งทำได้ในข้อมูลโค้ดต่อไปนี้
เปิดขึ้นมา scratch/myfirst.cc ในโปรแกรมแก้ไขที่คุณชื่นชอบ และเพิ่มบรรทัด
NS_LOG_INFO ("Creating Topology");
ก่อนถึงบรรทัด

NodeContainer nodes;
nodes.Create (2);

ตอนนี้รวบรวมสคริปต์โดยใช้ WAFและล้างตัวแปร NS_LOG เพื่อปิดใช้งานสตรีมการบันทึกที่เราเปิดใช้งานก่อนหน้านี้:

$ ./waf
$ export NS_LOG=
Теперь, если вы запустите скрипт,
$ ./waf --run scratch/myfirst

คุณจะไม่เห็นข้อความใหม่เนื่องจากไม่ได้เปิดใช้งานองค์ประกอบการบันทึกที่เกี่ยวข้อง (FirstScriptExample) หากต้องการดูข้อความของคุณ คุณต้องเปิดใช้งานองค์ประกอบการบันทึก FirstScriptตัวอย่าง โดยมีระดับไม่ต่ำกว่า NS_LOG_INFO หากคุณต้องการดูระดับการบันทึกเฉพาะนี้ คุณสามารถเปิดใช้งานได้เช่นนี้

$ export NS_LOG=FirstScriptExample=info

หากคุณรันสคริปต์ตอนนี้ คุณจะเห็นข้อความใหม่ “การสร้างโทโพโลยี”

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
Creating Topology
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

5.2 การใช้อาร์กิวเมนต์บรรทัดคำสั่ง

5.2.1 การแทนที่ค่าแอตทริบิวต์เริ่มต้น

อีกวิธีหนึ่งในการเปลี่ยนพฤติกรรมของสคริปต์ ns-3 โดยไม่ต้องแก้ไขหรือสร้างคือการใช้อาร์กิวเมนต์บรรทัดคำสั่ง เรามีกลไกในการแยกวิเคราะห์อาร์กิวเมนต์บรรทัดคำสั่งและตั้งค่าตัวแปรท้องถิ่นและส่วนกลางโดยอัตโนมัติตามผลลัพธ์

ขั้นตอนแรกในการใช้ระบบอาร์กิวเมนต์บรรทัดคำสั่งคือการประกาศ parser บรรทัดคำสั่ง สิ่งนี้ค่อนข้างง่ายที่จะทำ (ในโปรแกรมหลักของคุณ) ดังในโค้ดต่อไปนี้

int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}

ตัวอย่างสองบรรทัดง่ายๆ นี้มีประโยชน์มากในตัวมันเอง โดยจะเปิดประตูสู่ระบบตัวแปรและคุณลักษณะส่วนกลางของ ns-3 มาเพิ่มโค้ดสองบรรทัดที่จุดเริ่มต้นของฟังก์ชันสคริปต์หลัก scratch/myfirst.cc- ต่อไปเราจะคอมไพล์สคริปต์และรันมัน เมื่อรันเราจะขอความช่วยเหลือดังนี้

$ ./waf --run "scratch/myfirst --PrintHelp"

คำสั่งนี้จะถาม Waf เรียกใช้สคริปต์ เกา/ครั้งแรกของฉัน และส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่ง —ช่วยพิมพ์- เครื่องหมายคำพูดจำเป็นต้องระบุว่าอาร์กิวเมนต์มีไว้สำหรับโปรแกรมใด ตัวแยกวิเคราะห์บรรทัดคำสั่งจะตรวจจับอาร์กิวเมนต์ —ช่วยพิมพ์ และจะแสดงคำตอบว่า

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.

ตอนนี้เรามาดูตัวเลือกกัน —คุณลักษณะการพิมพ์- เราได้กล่าวถึงระบบแอตทริบิวต์ ns-3 แล้วเมื่อศึกษาสคริปต์ first.cc เราได้เห็นบรรทัดของโค้ดต่อไปนี้

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

และพวกเขาก็พูดอย่างนั้น อัตราข้อมูล จริงๆ แล้วเป็นคุณลักษณะ PointToPointNetDevice- ลองใช้ parser อาร์กิวเมนต์บรรทัดคำสั่งเพื่อดูแอตทริบิวต์ PointToPointNetDevice- รายการความช่วยเหลือระบุสิ่งที่เราต้องจัดเตรียมให้ รหัสประเภท- นี่คือชื่อของคลาสที่มีคุณลักษณะที่สนใจ ในกรณีของเรามันจะเป็น ns3::PointToPointNetDevice- ก้าวต่อไปกันเถอะเข้าสู่

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"

ระบบจะพิมพ์คุณสมบัติทั้งหมดของอุปกรณ์เครือข่ายประเภทนี้ คุณจะเห็นว่าในบรรดาคุณลักษณะในรายการคือ

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
The default data rate for point to point links

นี่เป็นค่าเริ่มต้นที่ระบบจะใช้เมื่อสร้างออบเจ็กต์ PointToPointNetDevice- เราจะแทนที่ค่าเริ่มต้นนี้โดยใช้พารามิเตอร์ คุณลักษณะ в PointToPointHelper สูงกว่า ลองใช้ค่าเริ่มต้นสำหรับอุปกรณ์และช่องสัญญาณแบบจุดต่อจุด ในการดำเนินการนี้ เราจะลบการโทรออก ตั้งค่าคุณสมบัติอุปกรณ์ и ตั้งค่า ChannelAttribute ของ myfirst.ccซึ่งเรามีอยู่ในไดเร็กทอรีที่สะอาด

สคริปต์ของคุณควรประกาศตอนนี้ PointToPointHelper และไม่ต้องดำเนินการติดตั้งใดๆ ดังตัวอย่างด้านล่าง

...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...

ไปข้างหน้าและสร้างสคริปต์ใหม่ด้วย Waf (./waff) และย้อนกลับไปรวมรายการบางส่วนจากแอปพลิเคชันเซิร์ฟเวอร์ UDP echo และรวมคำนำหน้าเวลาด้วย

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

หากคุณเรียกใช้สคริปต์ คุณจะเห็นผลลัพธ์ต่อไปนี้:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

โปรดจำไว้ว่าครั้งสุดท้ายที่เราดูเวลาจำลอง ช่วงเวลาที่เซิร์ฟเวอร์ echo ได้รับแพ็กเก็ตคือ 2,00369 วินาที

2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1

ตอนนี้เขาได้รับแพ็กเก็ตใน 2.25732 วินาที เนื่องจากเราเพียงรีเซ็ตอัตราข้อมูล PointToPointNetDevice จากห้าเมกะบิตต่อวินาทีเป็นค่าเริ่มต้น ซึ่งก็คือ 32768 บิตต่อวินาที หากเราแทนที่ DataRate ใหม่โดยใช้บรรทัดคำสั่ง เราก็สามารถเร่งการจำลองของเราได้อีกครั้ง เราจะดำเนินการดังต่อไปนี้ ตามสูตรที่แสดงโดยองค์ประกอบ help:

$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"

สิ่งนี้จะส่งคืนแอตทริบิวต์ DataRate กลับเป็นค่าเริ่มต้นที่ห้าเมกะบิตต่อวินาที คุณแปลกใจกับผลลัพธ์หรือไม่? ปรากฎว่าเพื่อที่จะคืนพฤติกรรมดั้งเดิมของสคริปต์ เราต้องตั้งค่าการหน่วงเวลาของช่องสัญญาณให้ตรงกับความเร็วแสงด้วย เราสามารถขอให้ระบบบรรทัดคำสั่งพิมพ์คุณลักษณะของช่องสัญญาณได้ เช่นเดียวกับที่เราทำกับอุปกรณ์เครือข่าย:

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"

เราจะพบว่าแอตทริบิวต์การหน่วงเวลาของช่องสัญญาณมีการตั้งค่าดังนี้:

--ns3::PointToPointChannel::Delay=[0ns]:
Transmission delay through the channel

จากนั้นเราสามารถตั้งค่าเริ่มต้นทั้งสองนี้ผ่านระบบบรรทัดคำสั่งได้

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

ในกรณีนี้ เราจะกู้คืนเวลาที่เรามีเมื่อเราตั้งค่า DataRate และ Delay ในสคริปต์อย่างชัดเจน:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.00369s Received 1024 bytes from 10.1.1.1
2.00369s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

โปรดทราบว่าเซิร์ฟเวอร์จะได้รับแพ็กเก็ตอีกครั้งหลังจาก 2,00369 วินาที จริงๆ แล้วเราสามารถตั้งค่าคุณลักษณะใดๆ ที่ใช้ในสคริปต์ได้ด้วยวิธีนี้ โดยเฉพาะอย่างยิ่ง เราสามารถตั้งค่าแอตทริบิวต์ MaxPackets ให้เป็นค่าที่ไม่ใช่ค่าเดียวได้ UdpEchoClient.

คุณจะใช้มันอย่างไร? ให้มันลอง. โปรดจำไว้ว่าคุณต้องใส่ความคิดเห็นถึงจุดที่เราแทนที่ค่าแอตทริบิวต์เริ่มต้นและตั้งค่าไว้อย่างชัดเจน MaxPackets ในสคริปต์ จากนั้นคุณต้องสร้างสคริปต์ใหม่ คุณยังสามารถใช้บรรทัดคำสั่งเพื่อรับความช่วยเหลือด้านไวยากรณ์สำหรับการตั้งค่าแอตทริบิวต์เริ่มต้นใหม่ได้ เมื่อคุณเข้าใจสิ่งนี้แล้ว คุณสามารถควบคุมจำนวนแพ็คเกจที่แสดงบนบรรทัดคำสั่งได้ เนื่องจากเราเป็นคนขยัน บรรทัดคำสั่งของเราจึงควรมีลักษณะดังนี้:

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

คำถามธรรมชาติที่เกิดขึ้น ณ จุดนี้ก็คือ จะรู้ได้อย่างไรว่าคุณลักษณะทั้งหมดนี้มีอยู่จริง อีกครั้งระบบบรรทัดคำสั่งมีฟังก์ชันช่วยเหลือสำหรับเรื่องนี้ หากเราขอความช่วยเหลือจากบรรทัดคำสั่ง เราควรเห็น:

$ ./waf --run "scratch/myfirst --PrintHelp"
myfirst [Program Arguments] [General Arguments]
General Arguments:
--PrintGlobals: Print the list of globals.
--PrintGroups: Print the list of groups.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintTypeIds: Print all TypeIds.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintHelp: Print this help message.

หากคุณเลือกอาร์กิวเมนต์ "PrintGroups" คุณจะเห็นรายชื่อกลุ่มที่ลงทะเบียนทั้งหมด รหัสประเภท- ชื่อกลุ่มสอดคล้องกับชื่อของโมดูลในไดเร็กทอรีต้นทาง (แม้ว่าจะเป็นตัวพิมพ์ใหญ่ก็ตาม) การพิมพ์ข้อมูลทั้งหมดในครั้งเดียวอาจมีปริมาณมากเกินไป ดังนั้นจึงมีตัวกรองเพิ่มเติมเพื่อพิมพ์ข้อมูลตามกลุ่ม ดังนั้น ให้มุ่งเน้นไปที่โมดูลแบบจุดต่อจุดอีกครั้ง:

./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in group PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeader

ที่นี่คุณจะพบชื่อ TypeId ที่พร้อมใช้งานสำหรับการค้นหาแอตทริบิวต์ เช่น ใน
--PrintAttributes = ns3 :: PointToPointChannelดังที่แสดงด้านบน

อีกวิธีหนึ่งในการเรียนรู้เกี่ยวกับคุณลักษณะคือผ่าน Doxygen ns-3 มีหน้าเว็บที่แสดงรายการคุณลักษณะทั้งหมดที่ลงทะเบียนไว้ในเครื่องจำลอง

5.2.2 การจับคำสั่งของคุณเอง

คุณยังสามารถเพิ่ม hooks ของคุณเองผ่านระบบบรรทัดคำสั่งได้ ทำได้ค่อนข้างง่ายโดยใช้วิธีแยกวิเคราะห์บรรทัดคำสั่ง เพิ่มมูลค่า.
ลองใช้คุณสมบัตินี้เพื่อระบุจำนวนแพ็คเกจที่จะแสดงในลักษณะที่แตกต่างไปจากเดิมอย่างสิ้นเชิง มาเพิ่มตัวแปรท้องถิ่นที่เรียกว่า nแพ็คเก็ต เข้าไปในฟังก์ชัน หลัก- เราจะตั้งค่าเป็นหนึ่งเพื่อให้ตรงกับพฤติกรรมเริ่มต้นก่อนหน้าของเรา เพื่อให้ตัวแยกวิเคราะห์บรรทัดคำสั่งเปลี่ยนค่านี้ เราจำเป็นต้องบันทึกค่านี้ในตัวแยกวิเคราะห์ เราทำสิ่งนี้โดยเพิ่มการโทร เพิ่มมูลค่า- ไปเปลี่ยนสคริปเลย scratch/myfirst.cc เพื่อเริ่มต้นด้วยโค้ดต่อไปนี้

int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
cmd.Parse (argc, argv);
...

เลื่อนลงไปที่จุดในสคริปต์ที่เราตั้งค่าแอตทริบิวต์ MaxPackets และเปลี่ยนเพื่อให้ตั้งค่าเป็นตัวแปร nPackets แทนที่จะเป็นค่าคงที่ 1 ดังที่แสดงด้านล่าง

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

ตอนนี้ ถ้าคุณรันสคริปต์และระบุอาร์กิวเมนต์ -PrintHelp คุณควรเห็นอาร์กิวเมนต์ผู้ใช้ใหม่ รายการบนจอวิธีใช้ เข้า,

$ ./waf --run "scratch/myfirst --PrintHelp"
Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.403s)
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.
User Arguments:
--nPackets: Number of packets to echo

หากคุณต้องการเปลี่ยนจำนวนแพ็กเก็ตที่ส่ง คุณสามารถทำได้โดยการตั้งค่าอาร์กิวเมนต์บรรทัดคำสั่ง - -nPackets

$ ./waf --run "scratch/myfirst --nPackets=2"

ตอนนี้คุณควรเห็นแล้ว

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
Sent 1024 bytes to 10.1.1.2
3.25732s Received 1024 bytes from 10.1.1.1
3.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

ตอนนี้คุณได้ส่งพัสดุสองชิ้นแล้ว ค่อนข้างง่ายใช่มั้ย?
คุณจะเห็นว่าในฐานะผู้ใช้ ns-3 คุณสามารถใช้ระบบอาร์กิวเมนต์บรรทัดคำสั่งเพื่อจัดการค่าส่วนกลางและคุณลักษณะได้ หากคุณเป็นผู้สร้างโมเดล คุณสามารถเพิ่มคุณลักษณะใหม่ให้กับออบเจ็กต์ของคุณได้ และคุณลักษณะเหล่านี้จะพร้อมใช้งานโดยอัตโนมัติสำหรับการกำหนดค่าโดยผู้ใช้ของคุณผ่านระบบบรรทัดคำสั่ง หากคุณเป็นผู้เขียนสคริปต์ คุณสามารถเพิ่มตัวแปรใหม่ให้กับสคริปต์ของคุณและเสียบเข้ากับระบบบรรทัดคำสั่งของคุณได้อย่างราบรื่น

5.3 การใช้ระบบติดตาม

จุดรวมของการสร้างแบบจำลองคือการสร้างผลลัพธ์สำหรับการศึกษาต่อไป และระบบติดตาม ns-3 เป็นกลไกหลักสำหรับสิ่งนี้ เนื่องจาก ns-3 เป็นโปรแกรม C++ จึงสามารถใช้วิธีมาตรฐานในการสร้างเอาต์พุตจากโปรแกรม C++ ได้:

#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}

คุณยังสามารถใช้โมดูลการบันทึกเพื่อเพิ่มโครงสร้างเล็กๆ น้อยๆ ให้กับโซลูชันของคุณได้ มีปัญหาที่ทราบมากมายที่เกิดจากแนวทางนี้ และดังนั้นเราจึงจัดให้มีระบบย่อยการติดตามเหตุการณ์ทั่วไปเพื่อแก้ไขปัญหาเหล่านี้

เป้าหมายหลักของระบบติดตาม ns-3 คือ:

  • สำหรับงานพื้นฐาน ระบบการติดตามควรอนุญาตให้ผู้ใช้สร้างการติดตามมาตรฐานสำหรับแหล่งที่มายอดนิยม และเลือกออบเจ็กต์ที่สร้างการติดตาม

  • ผู้ใช้ระดับกลางควรสามารถขยายระบบการติดตามเพื่อเปลี่ยนรูปแบบเอาต์พุตที่สร้างขึ้นหรือแทรกแหล่งการติดตามใหม่ โดยไม่ต้องแก้ไขแกนจำลอง

  • ผู้ใช้ขั้นสูงสามารถแก้ไขแกนจำลองเพื่อเพิ่มแหล่งที่มาและซิงก์การติดตามใหม่ ระบบติดตาม ns-3 สร้างขึ้นบนหลักการของแหล่งที่มาและตัวรับสัญญาณการติดตามที่เป็นอิสระ รวมถึงกลไกที่เป็นหนึ่งเดียวในการเชื่อมต่อแหล่งที่มากับผู้บริโภค

ระบบติดตาม ns-3 สร้างขึ้นบนหลักการของแหล่งติดตามและตัวรับที่เป็นอิสระ เช่นเดียวกับกลไกที่เป็นหนึ่งเดียวสำหรับการเชื่อมต่อแหล่งที่มากับเครื่องรับ แหล่งที่มาของการติดตามคือออบเจ็กต์ที่สามารถส่งสัญญาณเหตุการณ์ที่เกิดขึ้นในการจำลองและให้การเข้าถึงข้อมูลพื้นฐานที่น่าสนใจ ตัวอย่างเช่น แหล่งที่มาของการติดตามสามารถระบุเมื่ออุปกรณ์เครือข่ายได้รับแพ็กเก็ต และทำให้เนื้อหาของแพ็กเก็ตพร้อมใช้งานสำหรับผู้รับการติดตามที่สนใจ

แหล่งที่มาของการติดตามโดยตัวมันเองนั้นไร้ประโยชน์ เว้นแต่ว่าแหล่งที่มาเหล่านั้นจะ "เชื่อมโยง" กับส่วนอื่นๆ ของโค้ดที่ทำบางสิ่งที่มีประโยชน์กับข้อมูลที่มาจาก Sink จริงๆ ตัวติดตามคือผู้บริโภคของเหตุการณ์และข้อมูลที่ได้รับจากแหล่งที่มาของการติดตาม ตัวอย่างเช่น คุณสามารถสร้างช่องทางการติดตามที่จะ (เมื่อเชื่อมต่อกับแหล่งการติดตามของตัวอย่างก่อนหน้านี้) จะพิมพ์ส่วนที่สนใจในแพ็กเก็ตที่ได้รับ

เหตุผลสำหรับการแยกที่ชัดเจนนี้คือ เพื่อให้ผู้ใช้สามารถเชื่อมต่อประเภทซิงก์ใหม่กับแหล่งที่มาการติดตามที่มีอยู่ โดยไม่ต้องแก้ไขและคอมไพล์แกนจำลองใหม่ ดังนั้นในตัวอย่างข้างต้น ผู้ใช้สามารถกำหนดตัวติดตามใหม่ในสคริปต์ของตน และเชื่อมต่อกับแหล่งที่มาของการติดตามที่มีอยู่ซึ่งกำหนดไว้ในแกนการจำลองโดยการแก้ไขสคริปต์ผู้ใช้เท่านั้น

ในบทช่วยสอนนี้ เราจะพูดถึงแหล่งที่มาและซิงก์ที่กำหนดไว้ล่วงหน้าบางส่วน และแสดงให้เห็นว่าพวกเขาสามารถกำหนดค่าได้อย่างไรโดยใช้ความพยายามน้อยที่สุดในส่วนของผู้ใช้ ดูคู่มือ ns-3 หรือส่วนวิธีการสำหรับข้อมูลเกี่ยวกับการกำหนดค่าการติดตามขั้นสูง รวมถึงการขยายเนมสเปซการติดตามและการสร้างแหล่งที่มาของการติดตามใหม่

5.3.1 การติดตาม ASCII

ns-3 มีฟังก์ชันตัวช่วยที่จัดเตรียมระบบการติดตามระดับต่ำเพื่อช่วยคุณในเรื่องรายละเอียดเมื่อตั้งค่าการติดตามแพ็กเก็ตแบบธรรมดา หากคุณเปิดใช้งานคุณสมบัตินี้ คุณจะเห็นผลลัพธ์ในไฟล์ ASCII สำหรับผู้ที่คุ้นเคยกับเอาต์พุต ns-2 การติดตามประเภทนี้จะคล้ายกัน ออก.trซึ่งสร้างโดยสคริปต์จำนวนมาก

มาเริ่มธุรกิจกันและเพิ่มผลลัพธ์การติดตาม ASCII ให้กับสคริปต์ scratch/myfirst.cc ของเรา ทันทีก่อนที่จะสาย Simulator :: Run ()ให้เพิ่มบรรทัดโค้ดต่อไปนี้:
AsciiTraceHelper ascii;

pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

เช่นเดียวกับสำนวน ns-3 อื่นๆ โค้ดนี้ใช้อ็อบเจ็กต์ตัวช่วยเพื่อสร้างการติดตาม ASCII บรรทัดที่สองมีการเรียกเมธอดแบบซ้อนสองตัว วิธี "ภายใน" CreateFileStream() ใช้สำนวนวัตถุที่ไม่ระบุชื่อเพื่อสร้างวัตถุสตรีมไฟล์บนสแต็ก (โดยไม่มีชื่อวัตถุ) และส่งผ่านไปยังวิธีการที่เรียกว่า เราจะเจาะลึกเรื่องนี้ในอนาคต แต่สิ่งที่คุณต้องรู้ ณ จุดนี้ก็คือ คุณกำลังสร้างออบเจ็กต์ที่แสดงถึงไฟล์ที่เรียกว่า myfirst.tr และโอนไปที่ ns-3 เรามอบความไว้วางใจให้ ns-3 ดูแลออบเจ็กต์ที่สร้างขึ้นตลอดอายุการใช้งาน ในระหว่างนี้จะช่วยแก้ไขปัญหาที่เกิดจากข้อจำกัดที่ไม่ค่อยมีใครรู้จัก (โดยเจตนา) ที่เกี่ยวข้องกับตัวสร้างการคัดลอกออบเจ็กต์สตรีม C++

โทรภายนอก เปิดใช้งานAsciiAll() บอกผู้ช่วยว่าคุณต้องการรวมการติดตาม ASCII ในการจำลองของคุณสำหรับการเชื่อมต่ออุปกรณ์แบบจุดต่อจุดทั้งหมด และคุณต้องการให้ตัวรับการติดตาม (ที่ระบุ) บันทึกข้อมูลการเคลื่อนไหวของแพ็คเก็ตในรูปแบบ ASCII

สำหรับผู้ที่คุ้นเคยกับ ns-2 เหตุการณ์ที่ติดตามจะเทียบเท่ากับจุดติดตามที่รู้จักซึ่งบันทึกเหตุการณ์ "+", "-", "d" และ "r"
ตอนนี้คุณสามารถสร้างสคริปต์และรันได้จากบรรทัดคำสั่ง:

$ ./waf --run scratch/myfirst

เช่นเดียวกับหลายครั้งก่อนหน้านี้ คุณจะเห็นข้อความหลายข้อความจาก Waf จากนั้น "'สร้าง' เสร็จสิ้นเรียบร้อยแล้ว" พร้อมด้วยข้อความบางส่วนจากโปรแกรมที่กำลังทำงานอยู่

เมื่อรันโปรแกรมจะสร้างไฟล์ชื่อ myfirst.tr- เนื่องจากลักษณะของงาน Wafโดยค่าเริ่มต้น ไฟล์จะไม่ถูกสร้างขึ้นในไดเร็กทอรีในเครื่อง แต่ในไดเร็กทอรีระดับบนสุดของที่เก็บ หากคุณต้องการเปลี่ยนเส้นทางที่บันทึกการติดตาม คุณสามารถใช้พารามิเตอร์ Waf เพื่อระบุได้ --cwd- เราไม่ได้ดำเนินการนี้ ดังนั้น หากต้องการดูไฟล์การติดตาม ASCII myfirst.tr ในโปรแกรมแก้ไขที่คุณชื่นชอบ เราจะต้องไปที่ไดเรกทอรีระดับบนสุดของพื้นที่เก็บข้อมูลของเรา

กำลังแยกวิเคราะห์การติดตาม ASCII

มีข้อมูลมากมายในรูปแบบที่ค่อนข้างหนาแน่น แต่สิ่งแรกที่คุณต้องสังเกตก็คือไฟล์นั้นประกอบด้วยแต่ละบรรทัด สิ่งนี้จะมองเห็นได้ชัดเจนหากคุณขยายหน้าต่างการรับชมให้กว้างขึ้น

แต่ละบรรทัดในไฟล์สอดคล้องกับเหตุการณ์การติดตาม ในกรณีนี้ เราจะติดตามเหตุการณ์ในคิวการส่งข้อมูลที่มีอยู่ในอุปกรณ์เครือข่ายแบบจุดต่อจุดแต่ละจุดในการจำลอง คิวการส่งข้อมูลคือคิวที่แต่ละแพ็กเก็ตต้องผ่านสำหรับลิงก์แบบจุดต่อจุด โปรดทราบว่าแต่ละบรรทัดในไฟล์การติดตามเริ่มต้นด้วยอักขระตัวเดียว (และมีช่องว่างหลังจากนั้น) สัญลักษณ์นี้จะมีความหมายดังต่อไปนี้:

+: การดำเนินการเข้าคิวเกิดขึ้นบนคิวอุปกรณ์
-: การดำเนินการดึงข้อมูลองค์ประกอบเกิดขึ้นในคิวอุปกรณ์
d: แพ็กเก็ตถูกทิ้ง โดยทั่วไปเนื่องจากคิวเต็ม
r: อุปกรณ์เครือข่ายได้รับแพ็กเก็ต

มาดูบรรทัดแรกในไฟล์การติดตามให้ละเอียดยิ่งขึ้น ฉันจะแบ่งมันออกเป็นส่วนๆ (โดยมีการเยื้องเพื่อความชัดเจน) และหมายเลขบรรทัดทางด้านซ้าย:

0 +
1 2
2 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
3 ns3::PppHeader (
4   Point-to-Point Protocol: IP (0x0021))
6   ns3::Ipv4Header (
7     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
8     length: 1052 10.1.1.1 > 10.1.1.2)
9     ns3::UdpHeader (
10      length: 1032 49153 > 9)
11      Payload (size=1024)

ส่วนแรกของเหตุการณ์การติดตามเพิ่มเติม (บรรทัด 0) คือการดำเนินการ เรามีสัญลักษณ์ + ตรงนี้ ซึ่งตรงกับการดำเนินการเข้าคิวเพื่อส่งสัญญาณ ส่วนที่สอง (บรรทัดที่ 1) คือเวลาจำลอง ซึ่งแสดงเป็นวินาที คุณอาจจำสิ่งที่เราถามได้ UdpEchoClientApplication เริ่มส่งแพ็กเก็ตภายในสองวินาที ที่นี่เราเห็นการยืนยันว่าสิ่งนี้เกิดขึ้นจริง

ส่วนถัดไปของตัวอย่างการติดตาม (จากบรรทัดที่ 2) แสดงว่าแหล่งการติดตามใดที่สร้างเหตุการณ์นี้ (บ่งชี้การติดตามเนมสเปซ) คุณสามารถนึกถึงเนมสเปซการติดตามได้เหมือนกับที่คุณนึกถึงเนมสเปซของระบบไฟล์ รากของเนมสเปซคือ NodeList- ซึ่งสอดคล้องกับคอนเทนเนอร์ที่ได้รับการจัดการในโค้ด ns-3 หลัก ประกอบด้วยโหนดทั้งหมดที่สร้างขึ้นในสคริปต์ เช่นเดียวกับที่ระบบไฟล์สามารถมีไดเร็กทอรีอยู่ที่รากของมันได้ NodeList เราสามารถมีได้หลายโหนด ดังนั้นบรรทัด /NodeList/0 อ้างถึงโหนดว่างใน NodeList ซึ่งเรามักจะคิดว่าเป็น "โหนด 0" แต่ละโหนดมีรายการอุปกรณ์ที่ติดตั้งไว้ รายการนี้ตั้งอยู่ถัดไปในเนมสเปซ คุณจะเห็นว่าเหตุการณ์การติดตามนี้มาจาก รายการอุปกรณ์/0ซึ่งเป็นอุปกรณ์ว่างที่ติดตั้งในโหนด

สตริงย่อยถัดไป $ ns3 :: PointToPointNetDeviceบอกว่าอุปกรณ์ใดอยู่ที่ตำแหน่งศูนย์: รายการอุปกรณ์ของโหนดศูนย์ โปรดจำไว้ว่าการดำเนินการ + ที่พบในบรรทัด 0 หมายความว่ามีการเพิ่มองค์ประกอบในคิวการส่งของอุปกรณ์ สิ่งนี้สะท้อนให้เห็นในส่วนสุดท้ายของ "เส้นทางติดตาม": TxQueue/จัดคิว.

ส่วนที่เหลือในการติดตามควรจะค่อนข้างเข้าใจง่าย บรรทัดที่ 3-4 ระบุว่าแพ็กเก็ตถูกห่อหุ้มในโปรโตคอลแบบจุดต่อจุด บรรทัดที่ 5-7 แสดงว่าแพ็กเก็ตมีส่วนหัวเวอร์ชัน IP4 และมีต้นกำเนิดมาจากที่อยู่ IP 10.1.1.1 และมีไว้สำหรับ 10.1.1.2- บรรทัดที่ 8-9 แสดงว่าแพ็กเก็ตนี้มีส่วนหัว UDP และสุดท้ายบรรทัดที่ 10 แสดงว่าเพย์โหลดคือ 1024 ไบต์ที่คาดไว้

บรรทัดถัดไปในไฟล์การติดตามแสดงว่าแพ็กเก็ตเดียวกันถูกดึงออกจากคิวการส่งข้อมูลบนโหนดเดียวกัน

บรรทัดที่สามในไฟล์การติดตามแสดงว่าอุปกรณ์เครือข่ายบนโฮสต์เซิร์ฟเวอร์ echo ได้รับแพ็กเก็ต ฉันได้จำลองเหตุการณ์ด้านล่าง

0 r
1 2.25732
2 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
3   ns3::Ipv4Header (
4     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
5     length: 1052 10.1.1.1 > 10.1.1.2)
6     ns3::UdpHeader (
7       length: 1032 49153 > 9)
8       Payload (size=1024)

โปรดทราบว่าขณะนี้การดำเนินการติดตามเป็น r และเวลาการจำลองเพิ่มขึ้นเป็น 2,25732 วินาที หากคุณปฏิบัติตามบทช่วยสอนอย่างระมัดระวัง นั่นหมายความว่าคุณปล่อยให้ DataRate และ Link Delay ของอุปกรณ์เครือข่ายเป็นค่าเริ่มต้น กาลนี้ควรจะคุ้นเคยดังที่คุณเห็นในส่วนที่แล้ว

รายการเนมสเปซแหล่งที่มาของการติดตาม (บรรทัดที่ 2) ได้รับการแก้ไขเพื่อแสดงว่าเหตุการณ์นี้มาจากโหนด 1 (/NodeList/1) และแพ็กเก็ตได้รับจากแหล่งติดตาม (/แมคอาร์เอ็กซ์- การติดตามการเคลื่อนไหวของแพ็กเก็ตผ่านโทโพโลยีน่าจะค่อนข้างง่ายสำหรับคุณ โดยดูที่ร่องรอยที่เหลืออยู่ในไฟล์

5.3.2 ติดตาม PCAP

ตัวช่วยอุปกรณ์ ns-3 ยังสามารถใช้เพื่อสร้างไฟล์การติดตามในรูปแบบ .pcap ได้อีกด้วย อักษรย่อ พีซีแคป (โดยปกติจะเขียนด้วยตัวพิมพ์เล็ก) ย่อมาจากการจับแพ็กเก็ตและจริงๆ แล้วเป็น API ที่รวมการกำหนดรูปแบบไฟล์ .pcap โปรแกรมยอดนิยมที่สามารถอ่านและแสดงรูปแบบนี้ได้คือ Wireshark (เมื่อก่อนเรียกว่า. ไม่มีตัวตน- อย่างไรก็ตาม มีเครื่องวิเคราะห์การติดตามการรับส่งข้อมูลจำนวนมากที่ใช้รูปแบบแพ็กเก็ตนี้ เราขอแนะนำให้ผู้ใช้ใช้เครื่องมือมากมายเพื่อวิเคราะห์การติดตาม pcap ในบทช่วยสอนนี้ เราจะเน้นไปที่การดูการติดตาม pcap โดยใช้ tcpdump.

การเปิดใช้งานการติดตาม pcap ทำได้โดยใช้โค้ดหนึ่งบรรทัด

pointToPoint.EnablePcapAll ("myfirst");

วางบรรทัดโค้ดนี้หลังโค้ดติดตาม ASCII ที่เราเพิ่งเพิ่มเข้าไป scratch/myfirst.cc- โปรดทราบว่าเราส่งเฉพาะสตริง "myfirst" ไม่ใช่ "myfirst.pcap" หรืออะไรที่คล้ายกัน เนื่องจากพารามิเตอร์เป็นคำนำหน้า ไม่ใช่ชื่อไฟล์แบบเต็ม ในระหว่างการจำลอง ผู้ช่วยจะสร้างไฟล์การติดตามสำหรับอุปกรณ์แบบจุดต่อจุดแต่ละเครื่อง ชื่อไฟล์จะถูกสร้างขึ้นโดยใช้คำนำหน้า หมายเลขโหนด หมายเลขอุปกรณ์ และส่วนต่อท้าย "พีซีแคป'

สำหรับสคริปต์ตัวอย่างของเรา เราจะเห็นไฟล์ชื่อ "myfirst-0-0.pcap"และ"myfirst-1-0.pcap" ซึ่งเป็นการติดตาม pcap สำหรับโหนด 0-อุปกรณ์ 0 และโหนด 1-อุปกรณ์ 0 ตามลำดับ เมื่อคุณเพิ่มบรรทัดโค้ดเพื่อเปิดใช้งานการติดตาม pcap แล้ว คุณสามารถเรียกใช้สคริปต์ได้ตามปกติ:

$ ./waf --run scratch/myfirst

หากคุณดูในไดเรกทอรีระดับบนสุดของการแจกจ่าย คุณจะเห็นไฟล์สามไฟล์: ไฟล์ติดตาม ASCII myfirst.trที่เราศึกษาก่อนหน้านี้คือไฟล์ myfirst-0-0.pcap и myfirst-1-0.pcap - ไฟล์ pcap ใหม่ที่เราเพิ่งสร้างขึ้น

อ่านเอาต์พุตด้วย tcpdump

ในตอนนี้ วิธีที่ง่ายที่สุดในการดูไฟล์ pcap คือการใช้ tcpdump

$ tcpdump -nn -tt -r myfirst-0-0.pcap
reading from file myfirst-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
tcpdump -nn -tt -r myfirst-1-0.pcap
reading from file myfirst-1-0.pcap, link-type PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024

ในกองขยะ myfirst-0-0.pcap (อุปกรณ์ไคลเอนต์) คุณจะเห็นว่าแพ็กเก็ต echo ถูกส่งหลังจากการจำลอง 2 วินาที หากคุณดูที่การถ่ายโอนข้อมูลครั้งที่สอง (myfirst-1-0.pcap) จะเห็นว่าได้รับแพ็กเก็ตในเวลา 2,257324 วินาที คุณจะเห็นในการถ่ายโอนข้อมูลครั้งที่สองว่าแพ็กเก็ตถูกส่งกลับในเวลา 2.257324 วินาที และในที่สุดไคลเอ็นต์จะได้รับแพ็กเก็ตกลับมาในการถ่ายโอนข้อมูลครั้งแรกในเวลา 2.514648 วินาที

การอ่านเอาท์พุตด้วย Wireshark

ถ้าคุณไม่คุ้นเคย Wiresharkมีเว็บไซต์ที่คุณสามารถดาวน์โหลดโปรแกรมและเอกสารประกอบได้: http://www.wireshark.org/. Wireshark เป็น GUI ที่สามารถใช้เพื่อแสดงไฟล์การติดตามเหล่านี้ หากคุณมี Wireshark คุณสามารถเปิดไฟล์การติดตามใดๆ และแสดงเนื้อหาราวกับว่าคุณได้จับแพ็กเก็ตโดยใช้เครื่องดมแพ็กเก็ต

ที่มา: will.com

เพิ่มความคิดเห็น