一、CSMA网络的拓扑结构
拓扑结构如下:
// Default Network Topology
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0
其中,n0与n1是点对点连接,n1~n4是个CSMA有线局域网。该网络实现n0经过n1,和n4进行通信。
二、函数代码注释和解析
2.1 准备部分
//标志是否启用了客户端应用程序和客户端服务器应用程序日志记录组件
bool verbose = true;
uint32_t nCsma = 3;
//配置可在命令行修改脚本参数
CommandLine cmd(__FILE__);
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;
2.2 构建网络拓扑
//创建两个P2P节点
NodeContainer p2pNodes;
p2pNodes.Create(2);
//声明一个节点容器,提取P2P的两节点中编号为1的节点,将其配置为CSMA节点,还包含CSMA网络的额外节点
NodeContainer csmaNodes;
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Create(nCsma);
//配置P2P信道的延迟及数据传输速率
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
//安装P2P网络设备到P2P网络节点
NetDeviceContainer p2pDevices; //创建网络设备
p2pDevices = pointToPoint.Install(p2pNodes); //连接节点与信道
//创建CSMA设备并连接CSMA设备到信道
CsmaHelper csma;
//设置CSMA传输速率和传播延迟,注意数据传输速率由channel属性指定,而非device属性,因为CSMA不允许同一信道上有多个不同数据率的设备
csma.SetChannelAttribute("DataRate", StringValue("100Mbps"));
csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560)));
//安装CSMA网卡到CSMA网络节点
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install(csmaNodes);
2.3 安装协议栈
//安装协议栈
InternetStackHelper stack;
stack.Install(p2pNodes.Get(0));
stack.Install(csmaNodes);
//为设备接口分配IP地址
Ipv4AddressHelper address;
//为P2P设备分配IP
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign(p2pDevices);
//为CSMA设备分配IP
address.SetBase("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign(csmaDevices);
2.4 安装应用层
//配置UDP服务器端口号为9
UdpEchoServerHelper echoServer(9);
//在csma网络中编号为csma的节点中安装服务端程序
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));
//在节点0(最左端的点)中安装客户端程序
ApplicationContainer clientApps = echoClient.Install(p2pNodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
2.5 设置路由
ns-3 提供了所谓的全局路由来帮助完成了设置路由的艰苦工作,而无需配置路由器。
每个节点都会像 OSPF 路由器一样,每个节点都会将信息直接传递给全局路由管理器,全局路由管理器会使用这些全局信息为每个节点构建路由表。设置这种形式的路由只需一个步骤:
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
2.6 PCAP数据追踪
pointToPoint.EnablePcapAll("second");
csma.EnablePcap("second", csmaDevices.Get(1), true);
//ture代表1节点采用混杂模式嗅探数据包
网络中收集跟踪信息有两种基本方法。一种方法是为每个网络设备创建一个跟踪文件,只存储该网络设备发出或消耗的数据包。另一种方法是选择其中一个设备,将其置于混杂模式。然后,这台设备会 "嗅探 "网络中的所有数据包,并将其存储到一个 pcap 文件中。例如,tcpdump 就是这样工作的。最后一个参数告诉 CSMA 助手是否在混杂模式下捕获数据包。
2.7 运行和清理
Simulator::Run();
Simulator::Destroy();
2.8 运行结果
./ns3 run second
但结果与官方文档不同,不知为何,有解决方法再更新
输出信息显示了UdpEcho应用的行为:2s时,节点0(10.1.1.1)发送了一个大小为1024B的数据包给节点4(10.1.1.4)。经过0.0118s(但官方文档为0.0078s),节点4成功接收到数据包后返回一个同样大小的数据包。再经过相同的时间,节点0接收到该返回数据包。
具体过程为:节点0通过PPP连接发送数据包至节点1,节点1已知数据包的目的IP地址,但并不知晓其MAC地址,它在 CSMA 网络(ff:ff:ff:ff:ff:ff:ff:ff:ff:ff)上广播(ARP协议),询问 IP 地址为 10.1.2.4 的设备。最右边的节点回复说它的 MAC 地址是 00:00:00:00:00:00:06。这时节点 2 并不直接参与此交换,而是在嗅探网络并报告它看到的所有流量。
通过/ns-3-dev文件下的pcap文件,可以具体的每个节点察觉的数据包信息。通过以下代码查看
tcpdump -nn -tt -r second-0-0.pcap //根据具体文件名进行修改
2.9 调整参数
1. 修改ncsma为4,这时服务器现在被重新定位到 CSMA 节点的最后一个,即 10.1.2.5,而不是默认情况下的 10.1.2.4。
./ns3 run "second --nCsma=4"
官方文档结果为
可以看到结果也相差甚远,从client到server的时间理应增加,但实测出的结果却是减少,但相比之下信息回复的时间都比发送的时间更长,不知为何。
2. 修改ncsma为100,服务器被重新定位到10.1.2.101。
./ns3 run "second --nCsma=100"
官方文档结果
此时信息从server到client的时间相比于发送时间的比值都变得更大了
2.10 可视化呈现
采用Pyviz工具进行可视化呈现,安装步骤参考【ns-3】零基础安装教程 和 ns-3打开PyViz可视化工具
- 安装Python可视化器和绑定(ns-3.37及更新版本):cppyy Python模块和Pyviz依赖
python3 -m pip install --user cppyy
sudo apt install gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3
-
修改配置选项,打开python绑定配置
./ns3 configure --build-profile=debug --enable-examples --enable-tests --enable-python-bindings
运行上述命令后,我们可以发现python绑定和PyViz可视化工具均以打开:
- 重新编译ns3(过程需要几分钟)
./ns3
重新编译之后即可使用可视化工具
./ns3 run second --vis
结果图如下:
补充:
官方文档还介绍了另一种获取节点编号的方法,主要用于ncsma较大的情况。该方法是认识到 NodeContainers 包含指向 ns-3 节点对象的指针。节点对象有一个名为 GetId 的方法,它将返回该节点的 ID,也就是我们要查找的节点编号。让我们查看一下 Node 的 Doxygen 并找到该方法,它在 ns-3 核心代码中的位置比我们目前看到的要远。具体可查看官方文档,在接近7.2的部分。