转自:http://blog.sina.com.cn/s/blog_7ec2ab360102wxgi.html
NS3中提供了CSMA的网络设备和信道。
NS3 CSMA设备模仿了一个简单的以太网网络。一个真正的以太网用带有指数退避算法的CSMA/CD(带冲突检测的载波监听多路访问技术)来共享传输媒介。NS3 CSMA设备和信道模型只是其子集。
正如之前构建点对点拓扑中的PointToPointHelper,这里我们将看到类似的CSMA Helper。这些Helper的操作都类似。
在examples/tutorial目录下的second.cc脚本,是之前的first.cc的升级版,我们在原来的点到点仿真中添加了CSMA进去。
下面,我们来看一下代码。
一.second.cc代码
#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
//n0、n1是点到点,右边是n1、n2、n3、n4是总线形局域网
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ================
// LAN 10.1.2.0 LAN上的节点数可以随意改变,但必须是两个以上
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); // 定义一个日志组件
int
main (int argc, char *argv[])
{
bool verbose = true; //用verbose flag 判定UdpEchoClientApplication和UdpEchoServerApplication日志组件是否启用。当verbose为真时,启用日志。
uint32_t nCsma = 3; //因为CSMA机制,所以必须存在两个以上的节点。nCsma代表了额外的节点或者设备的数量。如果nCsma=1,那么代表一共有两个节点,nCsma=3,则一共有4个节点。
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of "extra" CSMA nodes/devices", nCsma); //向命令行参数系统添加nCsma属性
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose); //向命令行参数系统添加verbose属性
cmd.Parse (argc,argv);
if (verbose)
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1 : nCsma; //为了确保nCsma不等于0
NodeContainer p2pNodes; //创建两个p2p节点对象,并创建两个节点
p2pNodes.Create (2);
NodeContainer csmaNodes; //创建CSMA节点对象
csmaNodes.Add (p2pNodes.Get (1)); //从p2p节点容器中取出序号为1的节点同时加到CSMA节点容器中,即有一个节点即是p2p节点,又是CSMA节点,该节点同时连接两种网络。
csmaNodes.Create (nCsma); //创建CSMA节点来组成CSMA网络,其中CSMA网络中的节点数为nCsma+1
PointToPointHelper pointToPoint; //设置设备和信道参数
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer p2pDevices; //创建p2p网络设备对象
p2pDevices = pointToPoint.Install (p2pNodes); //安装p2p网络设备到p2p节点上
CsmaHelper csma; //类似于PointToPointHelper。CsmaHelper用于创建和连接CSMA设备和信道。
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); //注意!DataRate是由SetChanelAttribute()方法设置!那是因为一个真实的CSMA网络不允许同一个信道上有多个不同数据速率的设备!
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); //设置信道时延
NetDeviceContainer csmaDevices; //创建CSMA网络设备对象,并安装在CSMA节点上
csmaDevices = csma.Install (csmaNodes);
InternetStackHelper stack; //安装协议栈
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes); //p2p的第二节点包含在CSMA节点中
Ipv4AddressHelper address; //给设备接口安排IP地址
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices); //p2p节点的地址为:n0:10.1.1.1 n1:10.1.1.2
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices); //CSMA节点的地址为:n1:10.1.2.1 n2:10.1.2.2 n3:10.1.2.3 n4:10.1.2.4
UdpEchoServerHelper echoServer (9); //UDP服务端网络端口号为9
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); //将Server服务安装在CSMA网络中的最后一个节点上,nCsma是可变的,因此不能用3。
serverApps.Start (Seconds (1.0)); //应用在第1秒开始,在第10秒停止。
serverApps.Stop (Seconds (10.0));
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); //告诉echo客户端,服务端的地址是最后一个节点的地址。
echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); //设置最大数据包发送数
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0))); //时间间隔
echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); //数据包大小
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0)); //将客户端服务安装在p2p网络中的第一个节点
clientApps.Start (Seconds (2.0)); //应用在第2秒开始,在第10秒停止.
clientApps.Stop (Seconds (10.0));
Ipv4GlobalRoutingHelper::PopulateRoutingTables (); //全局路由管理器根据节点产生的链路通告为每个节点建立路由表
pointToPoint.EnablePcapAll ("second"); //创建pcap追踪文件,追踪p2p网络
csma.EnablePcap ("second", csmaDevices.Get (1), true); //追踪csma设备1,true表示是否开启promiscuous模式。
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
二.CSMA的两种trace方法
(一)trace全网数据
CSMA网络是一个多点到点网络。这意味着在一个共享媒介上有多个终端。每个终端都有一个网络设备与之连接。对于这样的网络,有两种收集追踪信息的方法。一个是为每个网络设备创建trace文件,并且只存储由该网络设备发出或接收的数据包。另一个方法是选择其中一个设备并且设置为promiscuous模式。这个单一的设备将嗅探网络中的全部数据包,并且将它们存储在一个单一的pcap文件中。本例使用方法2。
编译运行脚本后:
在ns-3.25目录下,会出现3个.pcap文件:
secon-0-0.pcap:p2p网络
链路类型:PPP代表Point-to-Point
secon-1-0.pcap:p2p网络
secon-2-0.pcap:CSMA网络
ARP:地址解析协议,Address Resolution Protocol。是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
链路类型:EN10MB代表以太网
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// point-to-point | | | |
// ============
// LAN 10.1.2.0
分析:n1想要发送数据包给IP地址为10.1.2.4的节点,但是它不知道该节点的MAC地址。于是,n1在CSMA网络广播询问IP地址为10.1.2.4的设备。对应的节点就回应n1说自己的MAC地址是00:00:00:00:00:06。n2并没有直接涉及此次信息交换,但是却嗅探整个网络并且记录它所看见的所有数据流。
服务器收到echo请求并将数据包发回发送端。服务器知道这个地址是另一个网络的,通过IP地址10.1.2.1到达。
这是因为我们初始化了全局路由,全局路由将这些信息告知我们。但是echo服务器节点并不知道n1的MAC地址,所以它必须像n1那样ARP地址。
服务器将echo发到转发节点。
nCsma可以通过CommandLine来改变,例如:
当nCsma=5,服务器节点变为nCsma的最后一个节点,地址为10.1.2.6.
(二)trace单设备数据
之前的CSMA网络trace方法是让一个设备嗅探整个网络的数据包存于一个pcap文件中。当你不关心其他数据流,只想得到某个网络设备自身接收与发送的数据流时,可以利用下面的代码替换原来的EnablePcap代码:
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);
NS3 helpers提供将节点数和设备数作为参数的方法。由上述代码可知,我们要创造名为second的pcap文件,其中我们感兴趣的网络设备为0号。
为了得到节点标号,我们共有2种方法:1.节点在创建过程中按顺序从0开始以单调增长的方式被标号。2.根据节点创建顺序,手动计算节点标号。
在NS3中,Node对象有GetID()的方法可以返回节点ID,即节点标号。
false:代表节点的trace处于non-promiscuous模式。
最后一个CSMA节点是第nCsma+1个节点。
为了确保.pcap文件不会混淆,清除所有的pcap文件:
$ rm *.pcap
$ rm *.tr // 清除所有的trace文件和pcap文件
编译运行代码,并查看second-100-0.pcap文件:
可知,node100在echo交换中就是一个旁观者。它接收到的唯一的数据包是全CSMA网络广播的ARP请求。
-------------------------------完-----------------------------------