一、學(xué)習(xí)工具:
? ?1.? 參考資源:
????????a.《ns-3網(wǎng)絡(luò)模擬器基礎(chǔ)及應(yīng)用》
????????b. NS-3中文手冊
????????c. NS3官網(wǎng) https://www.nsnam.org/ ,下載ns-3 manual/ns-3 tutorial,
????????????在線ns-3 doxygen查找需要的函數(shù)跳轉(zhuǎn).??https://www.nsnam.org/docs/release/3.29/doxygen/
????2.? 代碼閱讀撰寫:
????????a. Windows下使用 source insight閱讀,編寫代碼可以自動(dòng)補(bǔ)全以及提示錯(cuò)誤;
????????b. Linux下使用 eclipse進(jìn)行代碼閱讀,debug調(diào)試等;
????????c. 兩者結(jié)合使用效果更佳。
二、學(xué)習(xí)內(nèi)容:NS3目錄下/examples/routing/dynamic-global-routing.cc
????1.? 代碼實(shí)現(xiàn)內(nèi)容(可查看本文件注釋,解釋的很詳細(xì)):
????????該動(dòng)態(tài)路由實(shí)現(xiàn)了點(diǎn)對點(diǎn)(point-to-point)和csma信道傳輸,在特定時(shí)間傳輸U(kuò)DP數(shù)據(jù)流,并設(shè)置節(jié)點(diǎn)ipv4接口的開關(guān)來實(shí)現(xiàn)動(dòng)態(tài)計(jì)算路由。
????????a. 拓?fù)浣Y(jié)構(gòu)如下:

????????b. 事件順序:
????????1s-16s 第一個(gè)CBR/UDP數(shù)據(jù)流從n1-n6,10s-16s第二個(gè)CBR/UDP數(shù)據(jù)流從n1-n6;在準(zhǔn)備階段,會預(yù)先計(jì)算全局路由,n1-n6的點(diǎn)對點(diǎn)最短路徑;
????????1s:第一個(gè)n1-n6的數(shù)據(jù)流開啟;
????????2s:n1節(jié)點(diǎn)關(guān)閉down,n1-n6鏈路斷開,n1和n6重新計(jì)算路徑,n1-n2-n5-n6;
????????4s:n1節(jié)點(diǎn)打開up,n1-n6鏈路重新連接,n1和n6重新計(jì)算路徑,n1-n6;
????????6s:n6節(jié)點(diǎn)關(guān)閉down,n1-n6鏈路斷開,n1和n6重新計(jì)算路徑,n1-n2-n5-n6;
????????8s:n6節(jié)點(diǎn)打開up,n1-n6鏈路重新連接,n1和n6重新計(jì)算路徑,n1-n6;
????????10s:第一個(gè)數(shù)據(jù)流停止傳輸;
????????11s:第二個(gè)數(shù)據(jù)流開始傳輸;
????????12s:n1節(jié)點(diǎn)關(guān)閉down,n1-n6鏈路斷開,n1和n6重新計(jì)算路徑,n1-n2-n5-n6;
????????14s:n1節(jié)點(diǎn)打開up,n1-n6鏈路重新連接,n1和n6重新計(jì)算路徑,n1-n6;
????????16s:第二個(gè)數(shù)據(jù)流停止傳輸。
? ????2. 代碼詳解,主函數(shù)部分
//設(shè)置全局路由能夠根據(jù)接口狀態(tài)觸發(fā)全局路由重新計(jì)算,默認(rèn)值為假,即關(guān)閉,在這里需要設(shè)置為真開啟。
Config::SetDefault("ns3::Ipv4GlobalRouting::RespondToInterfaceEvents", BooleanValue(true));
//日志,創(chuàng)建節(jié)點(diǎn)。
?NS_LOG_INFO("Create nodes.");
//使用NodeContainer 類創(chuàng)建七個(gè)節(jié)點(diǎn),節(jié)點(diǎn)編號從0開始。
//點(diǎn)對點(diǎn)信道的兩個(gè)節(jié)點(diǎn)組成一個(gè)節(jié)點(diǎn)容器,本例中,csma信道的四個(gè)節(jié)點(diǎn)還會組成一個(gè)節(jié)點(diǎn)容器,一共五個(gè)容器。
?NodeContainer c;
?c.Create (7);
?NodeContainer n0n2= NodeContainer (c.Get (0), c.Get (2));
?NodeContainer n1n2= NodeContainer (c.Get (1), c.Get (2));
?NodeContainer n5n6= NodeContainer (c.Get (5), c.Get (6));
?NodeContainer n1n6= NodeContainer (c.Get (1), c.Get (6));
?NodeContainern2345 = NodeContainer (c.Get (2), c.Get (3), c.Get (4), c.Get (5));
//為創(chuàng)建的每個(gè)節(jié)點(diǎn)安裝協(xié)議棧,InternetStackHelper類會為每個(gè)節(jié)點(diǎn)安裝一個(gè)網(wǎng)絡(luò)協(xié)議棧,主要是IP層。
InternetStackHelper internet;
internet.Install (c);
//日志,創(chuàng)建信道
NS_LOG_INFO ("Create channels.");
//使用PointToPointHelper類幫助創(chuàng)建p2p信道,即類+信道名稱。
PointToPointHelper p2p;
//調(diào)用PointToPointHelper類中的設(shè)置設(shè)備屬性函數(shù)SetDeviceAttribute 設(shè)置數(shù)據(jù)傳輸速率為5Mbps(這里的數(shù)據(jù)傳輸速率我個(gè)人認(rèn)為應(yīng)該是帶寬吧..),調(diào)用設(shè)置信道屬性函數(shù)SetChannelAttribute設(shè)置信道傳輸時(shí)延為2ms(參考ns3.PointToPointHelper.h)。
p2p.SetDeviceAttribute ("DataRate", StringValue("5Mbps"));
p2p.SetChannelAttribute ("Delay", StringValue("2ms"));
//應(yīng)用PointToPointHelper類中的NetDeviceContainer Install (NodeContainer c);函數(shù)將以上設(shè)置的屬性應(yīng)用于節(jié)點(diǎn)和信道中,并將對應(yīng)節(jié)點(diǎn)和信道放入NetDeviceContainer,即對應(yīng)的一個(gè)信道的兩個(gè)節(jié)點(diǎn)設(shè)置對應(yīng)的NetDevice,然后放入容器中。
NetDeviceContainer d0d2 = p2p.Install (n0n2);
//csma信道同理,調(diào)用CsmaHelper類進(jìn)行相應(yīng)設(shè)置操作。
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate",StringValue ("5Mbps"));
csma.SetChannelAttribute ("Delay", StringValue("2ms"));
NetDeviceContainer d2345 = csma.Install (n2345);
//設(shè)置IP地址
?NS_LOG_INFO("Assign IP Addresses.");
//調(diào)用 Ipv4AddressHelper類分配地址,唯一用戶可見的API是通過設(shè)置基IP地址和子網(wǎng)掩碼分配完成的,如下從10.1.1.0開始以子網(wǎng)掩碼為
255.255.255.0分配地址,地址默認(rèn)是從1開始單調(diào)增長。
?Ipv4AddressHelperipv4;
?ipv4.SetBase("10.1.1.0", "255.255.255.0");
//然后為上述設(shè)置的NetDevice容器中的每個(gè)節(jié)點(diǎn)設(shè)置一個(gè)地址,如下,節(jié)點(diǎn)n0對應(yīng)的設(shè)備d0的ip地址為10.1.1.1,節(jié)點(diǎn)n2對應(yīng)的設(shè)備d2的ip地址為10.1.1.2,若還有其他設(shè)備依次按照順序分配地址。
//完整函數(shù)為Ipv4InterfaceContainer中的Ipv4AddressHelper::Assign
(const NetDeviceContainer &c),使用Ipv4接口容器對象將一個(gè)IP地址同一個(gè)設(shè)備關(guān)聯(lián)起來。
//每個(gè)NetDevice都有一個(gè)關(guān)聯(lián)的IPv4接口,一個(gè)ipv4接口可以有一個(gè)或者與之相關(guān)的ipv4地址。
?ipv4.Assign(d0d2);
?ipv4.SetBase("10.1.3.0", "255.255.255.0");
?Ipv4InterfaceContaineri5i6 = ipv4.Assign (d5d6);
//調(diào)用Ipv4GlobalRoutingHelper類中的PopulateRoutingTables
()成員函數(shù),主要是建立路由數(shù)據(jù)庫然后對仿真中的所有節(jié)點(diǎn)初始化路由表,讓仿真中所有節(jié)點(diǎn)都會帶有一個(gè)路由器。
?Ipv4GlobalRoutingHelper::PopulateRoutingTables();
/*在ipv4-global-routing-helper.cc文件中對PopulateRoutingTables
()函數(shù)定義如下,實(shí)則是調(diào)用建立全局路由數(shù)據(jù)庫和初始化路由表的函數(shù)。
void
Ipv4GlobalRoutingHelper::PopulateRoutingTables (void)
{
?GlobalRouteManager::BuildGlobalRoutingDatabase ();
?GlobalRouteManager::InitializeRoutes ();
}
*/
//日志,開始創(chuàng)建應(yīng)用,
NS_LOG_INFO ("Create Applications.");
//指定端口
uint16_t port = 9;??// Discard port (RFC 863)
//應(yīng)用 OnOffHelper類中的OnOffHelper (std::string protocol, Address address); 函數(shù)幫助創(chuàng)建數(shù)據(jù)流
//參考inetsocketaddress.h中 InetSocketAddress (Ipv4Address ipv4, uint16_t
port);
??? 函數(shù)得到OnOffHelper上述函數(shù)中的地址參數(shù)Address
/*參考ipv4-interferce-container.cc中如下函數(shù)得到,i5i6對應(yīng)的ipv4接口容器中第一個(gè)接口(0代表i5,1代表n6節(jié)點(diǎn)的接口)的ipv4地址
Ipv4Address
Ipv4InterfaceContainer::GetAddress (uint32_t i, uint32_tj) const
*/
OnOffHelper onoff ("ns3::UdpSocketFactory",
????????????????????InetSocketAddress (i5i6.GetAddress (1), port));
//設(shè)置應(yīng)用屬性,即這里的UDP數(shù)據(jù)流,數(shù)據(jù)傳輸速率和數(shù)據(jù)包大小。還可以設(shè)置其他屬性,包括開關(guān)時(shí)間等。
onoff.SetConstantRate (DataRate ("2kbps"));
onoff.SetAttribute ("PacketSize", UintegerValue(50));
onoff2.SetAttribute ("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
onoff2.SetAttribute ("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
//為節(jié)點(diǎn)設(shè)置應(yīng)用并一起放置與ApplicationContainer這個(gè)容器中,參考o(jì)n-off-helper.h中原型函數(shù):
ApplicationContainer Install (Ptr<Node> node)
const;這里應(yīng)該是使用了c++中的隱式轉(zhuǎn)換,
利用NodeContainer中的Get()函數(shù)得到節(jié)點(diǎn)指針,這里是為節(jié)點(diǎn)1設(shè)置application應(yīng)用。
//然后設(shè)置開始時(shí)間,結(jié)束時(shí)間。
ApplicationContainer apps = onoff.Install (c.Get (1));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (10.0));
//利用packetsinkhelper幫助創(chuàng)建一個(gè)用于接收數(shù)據(jù)的對象,原函數(shù)為packet-sink-helper.h中的:
PacketSinkHelper (std::string protocol, Address address);
//Ipv4Address::GetAny (),返回值為0.0.0.0
//在創(chuàng)建的applicationcontainer應(yīng)用容器中,將接收數(shù)據(jù)對象綁定在節(jié)點(diǎn)n6上,意味著n6在1s-10s接收網(wǎng)絡(luò)中的數(shù)據(jù)。
PacketSinkHelper sink ("ns3::UdpSocketFactory",
????????????????????????Address (InetSocketAddress (Ipv4Address::GetAny (), port)));
apps = sink.Install (c.Get (6));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (10.0));
//對節(jié)點(diǎn)n1設(shè)置接口開關(guān),先從nodecontainer獲取節(jié)點(diǎn)轉(zhuǎn)化為指針n1
Ptr<Node> n1
= c.Get (1);
//inline
Ptr<T> GetObject (void) const;將參數(shù)轉(zhuǎn)化為一個(gè)指針
Ptr<Ipv4>
ipv41 = n1->GetObject<Ipv4> ();
uint32_t
ipv4ifIndex1 = 2;
//Simulator::Schedule (Time const &delay, const
Ptr<EventImpl> &event),設(shè)置事件,包括發(fā)生時(shí)間和事件類型,
//原型函數(shù)參考simulator.h中函數(shù):staticEventId Schedule (Time const &delay, MEM mem_ptr, OBJ obj, T1 a1);
// MEM mem_ptr成員方法指針,OBJ obj應(yīng)用成員方法的對象指針,T1 a1調(diào)用的對象。
//這里是對n1節(jié)點(diǎn)的接口設(shè)置開關(guān)狀態(tài)
Simulator::Schedule (Seconds(2),&Ipv4::SetDown,ipv41, ipv4ifIndex1);
Simulator::Schedule (Seconds (4),&Ipv4::SetUp,ipv41,ipv4ifIndex1);
//該部分就是計(jì)算計(jì)算路由,生成路由表等,關(guān)于路由下次詳細(xì)解釋。
Ipv4GlobalRoutingHelper g;
Ptr routingStream =Create ("dynamic-global-routing.routes",std::ios::out);
g.PrintRoutingTableAllAt (Seconds (12), routingStream);
//設(shè)置仿真參數(shù),代碼主函數(shù)完成。
NS_LOG_INFO ("Run Simulation.");
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");