一、代码解读
头文件如下:
#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/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"
拓扑图:
// Default Network Topology
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0
命令行参数与日志开启
//是否开启日志的标志
bool verbose = true;
//总线上的节点数= nCsma+1
uint32_t nCsma = 3;
//命令行输入 上面两个变量的值
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc, argv);
if (verbose)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma;
创建节点
NodeContainer p2pNodes;
p2pNodes.Create (2);
//与第一个例子不同的地方在于除了创建点对点节点外,还要创建csma节点,也就是总线上的节点
//因为p2p节点之一也在总线上,所以将其Add到csmaNodes中
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
设置网络设备和信道
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
//和点对点拓扑几乎一模一样的设置方式
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
网络协议栈
InternetStackHelper stack;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);
注意不要加多了,一共五个。不可以如下操作:
InternetStackHelper stack; stack.Install (p2pNodes); stack.Install (csmaNodes);
这样有一个既是p2p又是csma的节点被添加了两次协议
分配IP地址
Ipv4AddressHelper address;
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");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
应用程序设置与第一个例子类似
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
该实例是让p2p的第一个节点与总线上最后一个进行通信
由于我们实际上已经在这里构建了一个互联网络,因此我们需要某种形式的互联网络路由。ns-3提供了全局路由且无需配置即可使用。事实上,发生的事情是每个节点的行为都像是OSPF路由器一样,可以立即神奇地与幕后的所有其他路由器进行通信。
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
接下来,我们启用 pcap 跟踪。
pointToPoint.EnablePcapAll ("second");
csma.EnablePcap ("second", csmaDevices.Get (1), true);
CSMA 网络是多点对点网络。这意味着共享介质上可以(在本例中为)多个终结点。这些端点中的每一个都有一个与之关联的网络设备。从此类网络收集跟踪信息有两种基本替代方法。一种方法是为每个网络设备创建一个跟踪文件,并仅存储该网络设备发出或使用的数据包。另一种方法是选择其中一个设备并将其置于混杂模式。然后,该单个设备会“嗅探”网络中的所有数据包,并将它们存储在单个 pcap 文件中。例如,这就是工作原理。最后一个参数告诉 CSMA 帮助程序是否安排在混杂模式下捕获数据包。
代码的最后一部分只是运行并清理模拟,就像示例一样。
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
二、踪迹解析
运行完第二个实例后,会生成三个文件:
second-0-0.pcap second-1-0.pcap second-2-0.pcap
第一个:
$ tcpdump -nn -tt -r second-0-0.pcap
reading from file second-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
点对点节点0的追踪结果,可以看到PPP就是点对点链路,追踪到两个数据包,一个发送一个接收。
第二个:
$ tcpdump -nn -tt -r second-1-0.pcap
reading from file second-1-0.pcap, link-type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
点对点节点1的追踪结果,和上一个类似
第三个:
$ tcpdump -nn -tt -r second-2-0.pcap
reading from file second-2-0.pcap, link-type EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007710 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
可以看到链路类型变成EN10MB ,以太网类型,而且它需要地址解析协议。节点1知道IP地址,但不知道MAC地址,所以发起请求问谁是10.1.2.4,然后10.1.2.4将MAC地址回应给10.1.2.1,然后数据就能发送到10.1.2.4了。后面也是同理。
如果想从单个设备获取跟踪,可以设置为非混杂模式
pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false);
最后一个参数设为false,再来看看输出如何
$ tcpdump -nn -tt -r second-3-0.pcap
reading from file second-3-0.pcap, link-type EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.013815 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
非混杂模式旁观者,只能接收到广播到整个csma网络的ARP请求
$ tcpdump -nn -tt -r second-4-0.pcap
reading from file second-4-0.pcap, link-type EN10MB (Ethernet)
2.007698 ARP, Request who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, length 50
2.007698 ARP, Reply 10.1.2.4 is-at 00:00:00:00:00:06, length 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
2.013803 ARP, Request who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, length 50
2.013828 ARP, Reply 10.1.2.1 is-at 00:00:00:00:00:03, length 50
2.013828 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
而作为回声交换的实际参与者,混杂与非混杂输出结果是一样的。