当前位置: 首页 > 工具软件 > NS3 > 使用案例 >

NS3入门教程 以及 NS3 IEEE 802.15.7 CSMA/CA仿真代码

乌和畅
2023-12-01

 本文初衷

当我发现我必须要做NS3网络仿真的时候,我内心是拒绝的,一方面NS3完全没接触过,另一方面,C++语言接触也不是太多,感觉工作量好大。但是,真的是不做不行了。然后,我就到网上查一些关于NS3的仿真内容,入门什么的,感觉真的是好混乱啊,这个东西没有一个明确的教程,都是一些杂乱的CSDN和技术博客,看起来十分混乱,而且有些现成的代码都是好多好多年前的,让人很难受。所以,我就写了本文,希望能对你有所帮助,静下心来从头往后看吧。

第一步 linux系统的使用

既然你已经准备好进行NS3仿真了,那么就先静下心来安装一个NS3吧,但是NS3都是运行在linux系统下的,所以,你先要安装一个linux系统。linux系统你可以直接安装到电脑上,当然你也可以使用linux虚拟机进行安装(我是在虚拟机上安装的),推荐的虚拟软件是VMware,这个软件可以创建一个虚拟机,就是可以创建一个虚拟的linux系统,这样你就可以不影响自己windows系统的情况下,轻松的使用NS3了,你可以百度一下VMware安装教程,也可以使用我下面的百度云链接进行下载安装。VMware的使用在这里就不赘述了,安装和使用还是比较容易的。

链接:https://pan.baidu.com/s/1vKbVrIKDqueMdywsYFzZqA 
提取码:crv1 

第二步 NS3的安装

NS3的安装在网上有很多教程,可自行查找,我使用的版本是3.25

第三步 了解一下NS3开发流程

选择或开发相应模块:根据实际仿真对象和仿真场景选择相应的仿真模块:如果是有线局域网络(CSMA)还是无线局域网络(Wi-Fi);节点是否需要移动(mobility);使用何种应用程序(application);是否需要能量(energy)管理;使用何种路由协议(internet、aodv等);是否需要动画演示等可视化界面(visualizer、netanim)等。如果要搭建的网络是比较新的网络,如延迟容忍网络(DTN)等,需要开发设计协议,如路由协议、移动模型、能量管理模型等。

编写网络仿真脚本:有了相应的模块,就可以搭建网络仿真环境,ns3仿真脚本支持两种语言:C++和Python,但是两种语言的API接口是一样的,部分API可能还没有提供Python接口。编写ns3仿真脚本的大体过程如下。

  1. 生成节点:ns3中节点相当于一个空的计算机外壳,接下来要给这个计算机安装网络所需要的软硬件,如网卡、应用程序、协议栈等。
  1. 安装网络设备:不同的网络类型有不同的网络设备,从而提供不同的信道、物理层和MAC层,如CSMA、WiFi、WiMAX和point-to-point等。
  2. 安装协议栈:ns3网络中一般是TCP/IP协议栈,依据网络选择具体协议栈,如是UDP还是TCP,选择何种不同的路由协议(OLSR、AODV和Global等)并为其配置相应的IP地址,ns3即支持IPv4也支持IPv6。
  3. 安装应用层协议:依据选择的传输层协议选择相应的应用层协议,但有时需要自己编写应用层产生网络数据流量的代码。
  4. 开始仿真。

其中节点,网络设备,信道,应用程序的基本概念可以参照下面的这个文章

https://blog.csdn.net/weichanghu_/article/details/83306998

第四步 了解一下NS3的时间调度机制

https://blog.csdn.net/rustfree/article/details/84558058

第五步 NS3官网给了first.cc点对点,CSMA和wifi 的示例

通过这个示例你就可以了解大概的一个开发流程了

https://www.docin.com/p-2009136480.html

第六步 NS3 API

这个时候NS3的大概框架应该掌握的差不多了,那么就可以试着看下面的代码了,然后这个文档里会定义一些NS3的一些特殊类,可以到这里查找,以及一些模型,也可以在这里查找,值得注意是,这个API有些古老,有些特性已经变了,比如随机指数变量的使用。

https://www.nsnam.org/docs/release/3.7/doxygen/annotated.html

第七步 80215.7CSMA/CA的代码(仅供学习参考,不可全信,可能会有错误没有发现)

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
//头文件包含,在h文件中进行函数声明,在cpp文件中完成函数的实现
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
//定义命名空间
using namespace ns3;

NS_LOG_COMPONENT_DEFINE ("MacCsma");

class VLCNode;


class VLCChannel{
public:
//这应该是一个类的初始化函数
	VLCChannel(){
		state=2;
		ChannelSendTimeStamp=0;
		ChannelCcaTimeStamp=0;
//		AllPacketDelayPosition=0;
		collisionTimes=0;
		SumOfSuccessSendPackets=0;
		AllPacketDelayVector.clear();
	}
	int state;     //1-busy,2-free,3-sleep
	uint64_t ChannelSendTimeStamp;
	uint64_t ChannelCcaTimeStamp;
	uint64_t everySlotStartTimeStamp[16];
	uint64_t collisionTimes;
	EventId NextEndTxEventId;          //信道记录下一个结束发送事件ID,用于取消碰撞时先发送的数据包
	int TheNodeIdOfNextEndTxEventId;    //下一个结束发送事件的节点ID号,用于告知已经发送的节点产生碰撞
	VLCNode *nodes[20];          //数组下标为节点ID号

	void SetBusy()
	{
		state=1;
	}
	void SetFree()
	{
		state=2;
	}
//	uint64_t AllPacketDelay[100000];      //统计所有数据包延时
//	int AllPacketDelayPosition;         //插入延时信息位置

	uint64_t SumOfSuccessSendPackets;   //所有成功传输的数据量之和
	std::vector<uint64_t> AllPacketDelayVector;
};

class VLCNode{
public:
	VLCNode(){
		opticalClockDuration=5000;
		macMaxBE=5;
		macMinBE=3;
		NB=0;
		BE=macMinBE;
		macMaxRABackoffs=4;    //最大退避次数
		oneBackoffTime=20*opticalClockDuration;      //the time of one backoff
		rate=1000000;         //数据发送速率,对照协议MCSID取值不同设置
		ackWaitDuration=20+240+103;      //  PHY II 是20+5120+103=5243;PHY III 是20+5120+111=5251
//		macMaxFrameTotalWaitTime=10000000;   //不用


		wasSuspend=false;
		RandomAccessing=false;
		NodeId=0;
		numsOfCollision=0;
		NumOfLostPackets=0;
		NumsOfCCA=0;
		NumsOfCCABusy=0;
		NumsOfSendToChannel=0;
	}
	uint64_t NextSlotStartInterval(uint64_t timeStamp)
	{
		uint64_t result=0;
		for(int i=0;i<16;i++)
		{
			if(timeStamp<(channel->everySlotStartTimeStamp[i]))
			{
				result=channel->everySlotStartTimeStamp[i]-timeStamp;
				break;
			}
			else
			{
			}
		}
		return result;
	}
	void PacketCome(int packetSize)
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
		if(channel->state==3)
		{
//如果包来到的时候信道是不活跃状态,那么不进行随机接入函数调用,就先把包存到队列里就好了
			packetSizeList.push_back(packetSize);
			packetComeTimeStampList.push_back(Simulator::Now().GetNanoSeconds());
		}
		else
		{
			packetSizeList.push_back(packetSize);
			packetComeTimeStampList.push_back(Simulator::Now().GetNanoSeconds());
			if(!RandomAccessing)       
//如果当前节点没有正在进行随机接入则开始,如果已经有随机接入,则等待随机接入完成再进行
			{
				startRandomAccess();
			}
		}
	}
	void startRandomAccess()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
		RandomAccessing=true;
		if(!packetSizeList.empty())   //packet list is not empty
		{
			NB=0;
			BE=macMinBE;
			uint64_t afterBeaconTime=0;    //距离本次超帧中的信标帧时长
			afterBeaconTime=Simulator::Now().GetNanoSeconds()-channel->everySlotStartTimeStamp[0];
			uint64_t remainTime=afterBeaconTime%((uint64_t)20*opticalClockDuration);  //remainTime是第一次时间对齐需要的时间,加上退避时间即第一次CCA需要继续等待的时间
			Simulator::Schedule(NanoSeconds(remainTime),&VLCNode::firstBackoff,this);
		}
		else                  //packet list is empty
		{
//当包没有到来的时候,是什么也不执行的,等待packcome()函数再次调用
		}
	}
	void firstBackoff()
	{
		NS_LOG_FUNCTION(this<<"NodeId is:"<<NodeId);
//计算一下退避的时间,并在此时间后执行CCA过程
		uint64_t backoffs=rand()%((int)pow(2,BE)-1);
		uint64_t backoffTime=backoffs*oneBackoffTime;
		CCABusyTimeStamp=Simulator::Now().GetNanoSeconds();
		Simulator::Schedule(NanoSeconds(backoffTime),&VLCNode::CCA,this);
	}
	void CCA()
	{
		backoffTime=0;
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId<<"channelState"<<channel->state);
		uint64_t CcaInterval=Simulator::Now().GetNanoSeconds()-channel->ChannelCcaTimeStamp;
		NumsOfCCA++;     //统计节点进行CCA总次数
		if(CcaInterval<1000)   //CCA 时间间隔小于1000ns,认为碰撞发生
		{
			NumsOfSendToChannel++;
			collision();
		}
		else                //未发生碰撞正常执行CCA
		{

			NodeCcaTimeStamp=Simulator::Now().GetNanoSeconds();
			channel->ChannelCcaTimeStamp=NodeCcaTimeStamp;
			if(channel->state==1)   //channel is busy: nums of backoff ++
			{
				NB++;
				BE++;
				NumsOfCCABusy++;      //统计检测信道忙总次数
				if(BE>macMaxBE)
				{
					BE=macMaxBE;
				}
				else
				{
				}
//			NS_LOG_DEBUG("the NB is :"<<NB<<"the macMaxRABackoffs is"<<macMaxRABackoffs);
				if(NB>=macMaxRABackoffs)
				{
					failure();               //failure
				}
				else
				{
					CCABusyTimeStamp=Simulator::Now().GetNanoSeconds();
//					uint64_t remainSlotTime=NextSlotStartInterval(Simulator::Now().GetNanoSeconds());       //确定距离下一个时隙时间差
					uint64_t backoffs=rand()%((int)pow(2,BE)-1);
					backoffTime=backoffs*oneBackoffTime;
					CCAEvent=Simulator::Schedule(NanoSeconds(backoffTime),&VLCNode::CCA,this);
				}

			}

			else if(channel->state==2)   //channel is free : send
			{

				NumsOfSendToChannel++;
				//recieve ack time
				uint64_t getAckTime=(rand()%ackWaitDuration+400)*opticalClockDuration;  //接收到ACK的时间,400是长帧间间隔
				ACKAndIFSDuration=getAckTime;
				uint64_t thePacketSizeWithHeader=packetSizeList.front()+4+8;
				double onlyDataDuration=(double)thePacketSizeWithHeader*8*1000000000/(double)rate;
//				NS_LOG_DEBUG("onlyDataDuration is:"<<onlyDataDuration);
//				NS_LOG_DEBUG("getAckTime is:"<<getAckTime);
				uint64_t txDuration=onlyDataDuration+getAckTime;
				NodeSendTimeStamp=Simulator::Now().GetNanoSeconds();//节点开始发送时间戳
				channel->ChannelSendTimeStamp=NodeSendTimeStamp;//信道开始发送时间戳
			   EndTxEvent=Simulator::Schedule(NanoSeconds(txDuration),&VLCNode::endTx,this);
				channel->TheNodeIdOfNextEndTxEventId=NodeId;
				channel->NextEndTxEventId=EndTxEvent;
				channel->state=1;    //set channel is busy
			}
		}
	}

	void endTx()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
		RandomAccessing=false;
		if(channel->state==1)    //信道状态等于发送时设置的忙
		{
			if(NodeSendTimeStamp!=channel->ChannelSendTimeStamp)
			{
				collision();
			}
			else
			{
				channel->state=2;
				if(!packetComeTimeStampList.empty())
				{
					uint64_t delay=Simulator::Now().GetNanoSeconds()-packetComeTimeStampList.front();
//					NS_LOG_INFO("the delay with ack and LIFS is :"<<delay);
//					NS_LOG_INFO("the delay without ack and LIFS is :"<<delay-ACKAndIFSDuration);
//					channel->AllPacketDelay[channel->AllPacketDelayPosition]=delay-ACKAndIFSDuration;
//					channel->AllPacketDelayPosition++;

					channel->AllPacketDelayVector.push_back(delay-ACKAndIFSDuration);
				}
				if(!packetSizeList.empty())
				{
					uint64_t PacketSize=packetSizeList.front();//统计所有成功发送数据包
					channel->SumOfSuccessSendPackets=channel->SumOfSuccessSendPackets+PacketSize;
					packetSizeList.pop_front();
					packetComeTimeStampList.pop_front();
				}
				else
				{
				}
				if(!packetSizeList.empty())
				{
					startRandomAccess();
				}
			}
		}
		else if(channel->state==2)                 //信道状态被其他节点修改为空闲,发生碰撞
		{
			collision();
		}
		else                   //信道由超帧设置为休眠
		{

		}

	}
	void isNotifiedCollision()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
//		numsOfCollision++;
		channel->collisionTimes++;            //信道中记录所有节点碰撞次数
		NB++;
		BE++;
		if(BE>macMaxBE)
		{
			BE=macMaxBE;
		}
		else
		{
		}
//		NS_LOG_DEBUG("the NB is :"<<NB<<"the macMaxRABackoffs is"<<macMaxRABackoffs);
		if(NB>=macMaxRABackoffs)
		{
			failure();	             //failure
		}
		else
		{
//			CCABusyTimeStamp=Simulator::Now().GetNanoSeconds();
			uint64_t thePacketSizeWithHeader=packetSizeList.front()+4+8;
			double onlyDataDuration=(double)thePacketSizeWithHeader*8*1000000000/(double)rate;
			uint64_t sendDuration=onlyDataDuration+ackWaitDuration;
			Simulator::Schedule(NanoSeconds(sendDuration),&VLCChannel::SetFree,channel);   //被告知碰撞,在预期的接收ACK时间到达后将信道设置为空闲
//			uint64_t remainSlotTime=NextSlotStartInterval(Simulator::Now().GetNanoSeconds()+sendDuration);
			uint64_t backoffs=rand()%((int)pow(2,BE)-1);
			backoffTime=backoffs*oneBackoffTime;
			CCAEvent=Simulator::Schedule(NanoSeconds(sendDuration+backoffTime),&VLCNode::CCA,this);
		}
	}
	void collision()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
//		NS_LOG_INFO("collison");
//		EndTxEvent.Cancel();

		channel->NextEndTxEventId.Cancel();
//		NS_LOG_DEBUG("the channel->TheNodeIdOfNextEndTxEventId:"<<channel->TheNodeIdOfNextEndTxEventId);
		channel->nodes[channel->TheNodeIdOfNextEndTxEventId]->isNotifiedCollision();
//		channel->nodes[channel->TheNodeIdOfNextEndTxEventId]->collision();
//		channel->AllPacketDelayPosition--;

//		channel->AllPacketDelayVector.pop_back();
		numsOfCollision++;
		NB++;
		BE++;
		if(BE>macMaxBE)
		{
			BE=macMaxBE;
		}
		else
		{
		}
//		NS_LOG_DEBUG("the NB is :"<<NB<<"the macMaxRABackoffs is"<<macMaxRABackoffs);
		if(NB>=macMaxRABackoffs)
		{
			failure();	             //failure
		}
		else
		{
			CCABusyTimeStamp=Simulator::Now().GetNanoSeconds();
			uint64_t thePacketSizeWithHeader=packetSizeList.front()+4+8;
			double onlyDataDuration=(double)thePacketSizeWithHeader*8*1000000000/(double)rate;
			uint64_t sendDuration=onlyDataDuration+ackWaitDuration;
			Simulator::Schedule(NanoSeconds(sendDuration),&VLCChannel::SetFree,channel);   //碰撞发生后,在预期的接收ACK时间到达后将信道设置为空闲
//			uint64_t remainSlotTime=NextSlotStartInterval(Simulator::Now().GetNanoSeconds()+sendDuration);
			uint64_t backoffs=rand()%((int)pow(2,BE)-1);
			backoffTime=backoffs*oneBackoffTime;
			CCAEvent=Simulator::Schedule(NanoSeconds(backoffTime),&VLCNode::CCA,this);
		}
	}
	void failure()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
//		NS_LOG_INFO("one packet failure,NodeId"<<NodeId);
		NumOfLostPackets++;
		RandomAccessing=false;
		if(!packetSizeList.empty())
		{
			packetSizeList.pop_front();
			packetComeTimeStampList.pop_front();
		}
		else
		{
		}
		if(!packetSizeList.empty())
		{
			startRandomAccess();
		}
	}
	void suspend()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
		CCAEvent.Cancel();
		wasSuspend=true;
		CAPRestartAccessBackofftime=Simulator::Now().GetNanoSeconds()-CCABusyTimeStamp;
	}
	void CAPRestartAccess()
	{
		NS_LOG_FUNCTION(this<<"NodeId"<<NodeId);
		if(wasSuspend)       
//如果之前被中断,则根据剩余退避时间退避,也就是重新恢复之前的接入过程
		{
			wasSuspend=false;
			Simulator::Schedule(NanoSeconds(CAPRestartAccessBackofftime),&VLCNode::CCA,this);
		}
		else  //如果之前没有被中断,则看数据队列是否为空,非空则发起随机接入算法
		{
			if(!packetSizeList.empty())
			{
				startRandomAccess();
			}
		}
	}
	int NB;
	int BE;
	int macMaxBE;
	int macMinBE;
	int macMaxRABackoffs;
	int oneBackoffTime;      //the time of one backoff
//	int macMaxFrameTotalWaitTime;

	uint64_t CCABusyTimeStamp;
	uint64_t backoffTime;       //退比时长
	EventId CCAEvent;
	EventId EndTxEvent;
	uint64_t CAPRestartAccessBackofftime;   //下一个超帧开始,随机介入重启需要退避时间
	bool wasSuspend;                         //是否因为超帧结束导致CCA延迟,true是,false否
	int NumOfLostPackets;               //超过最大退避次数,失败
	bool RandomAccessing;               //true-正在进行随机接入过程,进入休眠需要suspend
	int NodeId;
	int numsOfCollision;
	int NumsOfCCA;
	int NumsOfCCABusy;
	int NumsOfSendToChannel;
	uint64_t NodeSendTimeStamp;
	uint64_t NodeCcaTimeStamp;
	uint64_t ACKAndIFSDuration;             //发送结束后帧间间隔和ACK花费时间

	uint64_t rate;
	uint64_t ackWaitDuration;
	int opticalClockDuration;
	std::deque<uint64_t> packetSizeList;
	std::deque<uint64_t> packetComeTimeStampList;
	VLCChannel *channel;
};
class SuperFrame{
public:
	SuperFrame(){
		BO=9;
		SO=8;
		state=true;        //true-active,false-sleep
		opticalClockDuration=5000;
		aBaseSuperframeDuration=60*16;
	}
	void start()
	{
		NS_LOG_FUNCTION(this);
//将superframe状态设置为true,这个状态表示活跃态CAP,false表示不活跃态sleep
//此CSMA代码不包含CFP阶段
		state=true;
//将信道设置为空闲,信道状态分为三个,1忙碌,2空闲,3睡眠sleep,就是上面的不活跃态
		channel->state=2;
//调用下面的方法,开始CAP阶段
		CAPToSleep();
	}
	void CAPToSleep()       //CAP start
	{
		NS_LOG_FUNCTION(this<<"CAP Start");
		state=true;
		channel->state=2;

//		channel->state=1;    //测试信道条件一直忙

		uint64_t SD=aBaseSuperframeDuration*pow(2,SO)*opticalClockDuration;
		uint64_t aSlotDuration=SD/16;
		uint64_t nowTime=Simulator::Now().GetNanoSeconds();
//		NS_LOG_DEBUG("nowTime="<<nowTime);
//		NS_LOG_DEBUG("SD="<<SD);
//		NS_LOG_DEBUG("aSlotDuration="<<aSlotDuration);
//一共有十六个时隙,所以要循环16次,根据信标beacon时间,定位接下来每一帧的开始时间
		for(int i=0;i<16;i++)
		{
			channel->everySlotStartTimeStamp[i]=nowTime+aSlotDuration*i;
//			NS_LOG_DEBUG("everySlotStartTimeStamp"<<channel->everySlotStartTimeStamp[i]);
		}
//			NS_LOG_DEBUG("CAP duration"<<SD);
//定义一个节点迭代器,对节点进行迭代
		std::vector<VLCNode *>::iterator it;
//每个节点执行CAP重传接入,可跳到CAPRestartAccess阅读
		for(it=m_Nodes.begin();it!=m_Nodes.end();it++)
		{
			(*it)->CAPRestartAccess();
		}
		Simulator::Schedule(NanoSeconds(SD),&SuperFrame::SleepToCAP,this);

	}
	void SleepToCAP()       //start Sleep
	{
		NS_LOG_FUNCTION(this<<"Start Sleep");
		state=false;

		std::vector<VLCNode *>::iterator it;
		for(it=m_Nodes.begin();it!=m_Nodes.end();it++)
		{
			if((*it)->RandomAccessing)
			{
				(*it)->suspend();
			}
		}

		channel->state=3;
		uint64_t SD=aBaseSuperframeDuration*pow(2,SO)*opticalClockDuration;
		uint64_t BI=aBaseSuperframeDuration*pow(2,BO)*opticalClockDuration;
		uint64_t SleepTime=BI-SD;
//		NS_LOG_DEBUG("Sleep duration"<<SleepTime);
		Simulator::Schedule(NanoSeconds(SleepTime),&SuperFrame::CAPToSleep,this);
	}

	int BO;
	int SO;
	bool state;        //true-active,false-sleep
	int aBaseSuperframeDuration;
	int opticalClockDuration;
	std::vector<VLCNode *>  m_Nodes;
	VLCChannel *channel;
};

int allPacketNums=0;
void testAddPacket(VLCNode *nodeId,int packetSize)
{
	nodeId->packetSizeList.push_back(packetSize);
	nodeId->packetComeTimeStampList.push_back(Simulator::Now().GetNanoSeconds());
}
void DelayMean(VLCChannel *channel)
{
	double sum=0;
	double mean=0;
	for(unsigned int i=0;i<channel->AllPacketDelayVector.size();i++)
	{
		sum=sum+channel->AllPacketDelayVector.at(i);
	}
	mean=(double)sum/(channel->AllPacketDelayVector.size());
	NS_LOG_INFO("the delay Mean="<<mean<<",nums of packet="<<allPacketNums);
	NS_LOG_INFO("the num of node1 failure:"<<channel->nodes[1]->NumOfLostPackets);
	NS_LOG_INFO("the num of node2 failure:"<<channel->nodes[2]->NumOfLostPackets);
	NS_LOG_INFO("the num of collision:"<<channel->collisionTimes);
	NS_LOG_INFO("the Throughput is:"<<(channel->SumOfSuccessSendPackets+12)*8/Simulator::Now().GetSeconds());
	NS_LOG_INFO("node 1 Probability of collision:"<<(float)(channel->nodes[1]->numsOfCollision)/(float)(channel->nodes[1]->NumsOfSendToChannel));
	NS_LOG_INFO("node 2 Probability of collision:"<<(float)(channel->nodes[2]->numsOfCollision)/(float)(channel->nodes[2]->NumsOfSendToChannel));
	NS_LOG_INFO("node 3 Probability of collision:"<<(float)(channel->nodes[3]->numsOfCollision)/(float)(channel->nodes[3]->NumsOfSendToChannel));
	NS_LOG_INFO("node 4 Probability of collision:"<<(float)(channel->nodes[4]->numsOfCollision)/(float)(channel->nodes[4]->NumsOfSendToChannel));
	NS_LOG_INFO("node 5 Probability of collision:"<<(float)(channel->nodes[5]->numsOfCollision)/(float)(channel->nodes[5]->NumsOfSendToChannel));
	NS_LOG_INFO("node 6 Probability of collision:"<<(float)(channel->nodes[6]->numsOfCollision)/(float)(channel->nodes[6]->NumsOfSendToChannel));
	NS_LOG_INFO("node 7 Probability of collision:"<<(float)(channel->nodes[7]->numsOfCollision)/(float)(channel->nodes[7]->NumsOfSendToChannel));
	NS_LOG_INFO("node 8 Probability of collision:"<<(float)(channel->nodes[8]->numsOfCollision)/(float)(channel->nodes[8]->NumsOfSendToChannel));
	NS_LOG_INFO("node 9 Probability of collision:"<<(float)(channel->nodes[9]->numsOfCollision)/(float)(channel->nodes[9]->NumsOfSendToChannel));
	NS_LOG_INFO("node 10 Probability of collision:"<<(float)(channel->nodes[10]->numsOfCollision)/(float)(channel->nodes[10]->NumsOfSendToChannel));

//	float SumPofCollision=(float)(channel->nodes[1]->numsOfCollision)/(float)(channel->nodes[1]->NumsOfSendToChannel)+
//			(float)(channel->nodes[2]->numsOfCollision)/(float)(channel->nodes[2]->NumsOfSendToChannel)+
//			(float)(channel->nodes[3]->numsOfCollision)/(float)(channel->nodes[3]->NumsOfSendToChannel)+
//			(float)(channel->nodes[4]->numsOfCollision)/(float)(channel->nodes[4]->NumsOfSendToChannel)+
//			(float)(channel->nodes[5]->numsOfCollision)/(float)(channel->nodes[5]->NumsOfSendToChannel);
	int j=0;
	float SumPofCollision=0;
	for(int i=1;i<11;i++)
	{
		if((channel->nodes[i]->NumsOfSendToChannel)!=0)
		{
			SumPofCollision=SumPofCollision+(float)(channel->nodes[i]->numsOfCollision)/(float)(channel->nodes[i]->NumsOfSendToChannel);
			j++;
		}
	}

	float PofCollision=SumPofCollision/(float)(j);
	NS_LOG_INFO("P of Collision:"<<PofCollision);

	NS_LOG_INFO("node 1 Probability of CCABusy:"<<(float)(channel->nodes[1]->NumsOfCCABusy)/(float)(channel->nodes[1]->NumsOfCCA));
	NS_LOG_INFO("node 2 Probability of CCABusy:"<<(float)(channel->nodes[2]->NumsOfCCABusy)/(float)(channel->nodes[2]->NumsOfCCA));
	NS_LOG_INFO("node 3 Probability of CCABusy:"<<(float)(channel->nodes[3]->NumsOfCCABusy)/(float)(channel->nodes[3]->NumsOfCCA));
	NS_LOG_INFO("node 4 Probability of CCABusy:"<<(float)(channel->nodes[4]->NumsOfCCABusy)/(float)(channel->nodes[4]->NumsOfCCA));
	NS_LOG_INFO("node 5 Probability of CCABusy:"<<(float)(channel->nodes[5]->NumsOfCCABusy)/(float)(channel->nodes[5]->NumsOfCCA));
	NS_LOG_INFO("node 6 Probability of CCABusy:"<<(float)(channel->nodes[6]->NumsOfCCABusy)/(float)(channel->nodes[6]->NumsOfCCA));
	NS_LOG_INFO("node 7 Probability of CCABusy:"<<(float)(channel->nodes[7]->NumsOfCCABusy)/(float)(channel->nodes[7]->NumsOfCCA));
	NS_LOG_INFO("node 8 Probability of CCABusy:"<<(float)(channel->nodes[8]->NumsOfCCABusy)/(float)(channel->nodes[8]->NumsOfCCA));
	NS_LOG_INFO("node 9 Probability of CCABusy:"<<(float)(channel->nodes[9]->NumsOfCCABusy)/(float)(channel->nodes[9]->NumsOfCCA));
	NS_LOG_INFO("node 10 Probability of CCABusy:"<<(float)(channel->nodes[10]->NumsOfCCABusy)/(float)(channel->nodes[10]->NumsOfCCA));

//	float SumPofCCABusy=(float)(channel->nodes[1]->NumsOfCCABusy)/(float)(channel->nodes[1]->NumsOfCCA)+
//			(float)(channel->nodes[2]->NumsOfCCABusy)/(float)(channel->nodes[2]->NumsOfCCA)+
//			(float)(channel->nodes[3]->NumsOfCCABusy)/(float)(channel->nodes[3]->NumsOfCCA)+
//			(float)(channel->nodes[4]->NumsOfCCABusy)/(float)(channel->nodes[4]->NumsOfCCA)+
//			(float)(channel->nodes[5]->NumsOfCCABusy)/(float)(channel->nodes[5]->NumsOfCCA);
	float SumPofCCABusy=0;
	for(int i=1;i<=j;i++)
	{
		SumPofCCABusy=SumPofCCABusy+(float)(channel->nodes[i]->NumsOfCCABusy)/(float)(channel->nodes[i]->NumsOfCCA);
	}


	float PofCCABusy=SumPofCCABusy/(float)(j);
	NS_LOG_INFO("P of CCABusy:"<<PofCCABusy);

	std::ofstream out("5NodeWithMean.txt",std::ios::app);
	out<<(channel->SumOfSuccessSendPackets+12)*8/Simulator::Now().GetSeconds()<<" "
			<<PofCollision<<" "<<PofCCABusy<<std::endl;

}
//void TestCapPacketCome(VLCNode *node,SuperFrame *superFrame)
//{
//	if(superFrame->state)
//	{
//		node->PacketCome(500);
//	}
//}
//*****************************************************************problem******************************************************************************
void PacketExponentialCome(VLCNode *node,double mean)
{
	double nextPacketComeInterval;
    Ptr<ExponentialRandomVariable> interval=CreateObject<ExponentialRandomVariable>();
    double bound=40.0;
    interval->SetAttribute("Mean",DoubleValue(mean));
    interval->SetAttribute("Bound",DoubleValue(bound));
    nextPacketComeInterval=interval->GetValue();
//	if(node->channel->state!=3)
//	{
		allPacketNums++;
		node->PacketCome(100);
//	}
	Simulator::Schedule(Seconds(nextPacketComeInterval),&PacketExponentialCome,node,mean);
}
//这是CSMA代码的主函数
int
main (int argc, char *argv[])
{

	long int mean=1;
	CommandLine cmd;
	cmd.AddValue("mean","the mean packet",mean);
	cmd.Parse(argc,argv);

  Time::SetResolution (Time::NS);

  RngSeedManager::SetSeed(time(0));

  LogComponentEnable ("MacCsma", LOG_LEVEL_INFO);
  LogComponentEnable("MacCsma", LOG_PREFIX_TIME);


  uint64_t opticalClockDurationValue;
  opticalClockDurationValue=5000;

  SuperFrame superFrame;
  superFrame.opticalClockDuration=opticalClockDurationValue;
  VLCChannel channel;

  VLCNode node1;
  node1.NodeId=1;
  node1.opticalClockDuration=opticalClockDurationValue;
  VLCNode node2;
  node2.NodeId=2;
  node2.opticalClockDuration=opticalClockDurationValue;
  VLCNode node3;
  node3.NodeId=3;
  node3.opticalClockDuration=opticalClockDurationValue;
  VLCNode node4;
  node4.NodeId=4;
  node4.opticalClockDuration=opticalClockDurationValue;
  VLCNode node5;
  node5.NodeId=5;
  node5.opticalClockDuration=opticalClockDurationValue;
  VLCNode node6;
  node6.NodeId=6;
  node6.opticalClockDuration=opticalClockDurationValue;
  VLCNode node7;
  node7.NodeId=7;
  node7.opticalClockDuration=opticalClockDurationValue;
  VLCNode node8;
  node8.NodeId=8;
  node8.opticalClockDuration=opticalClockDurationValue;
  VLCNode node9;
  node9.NodeId=9;
  node9.opticalClockDuration=opticalClockDurationValue;
  VLCNode node10;
  node10.NodeId=10;
  node10.opticalClockDuration=opticalClockDurationValue;



  node1.channel=&channel;
  node2.channel=&channel;
  node3.channel=&channel;
  node4.channel=&channel;
  node5.channel=&channel;
  node6.channel=&channel;
  node7.channel=&channel;
  node8.channel=&channel;
  node9.channel=&channel;
  node10.channel=&channel;

  channel.nodes[1]=&node1;
  channel.nodes[2]=&node2;
  channel.nodes[3]=&node3;
  channel.nodes[4]=&node4;
  channel.nodes[5]=&node5;
  channel.nodes[6]=&node6;
  channel.nodes[7]=&node7;
  channel.nodes[8]=&node8;
  channel.nodes[9]=&node9;
  channel.nodes[10]=&node10;


  superFrame.channel=&channel;
  superFrame.m_Nodes.push_back(&node1);
  superFrame.m_Nodes.push_back(&node2);
  superFrame.m_Nodes.push_back(&node3);
  superFrame.m_Nodes.push_back(&node4);
  superFrame.m_Nodes.push_back(&node5);
  superFrame.m_Nodes.push_back(&node6);
  superFrame.m_Nodes.push_back(&node7);
  superFrame.m_Nodes.push_back(&node8);
  superFrame.m_Nodes.push_back(&node9);
  superFrame.m_Nodes.push_back(&node10);


//此时,调用superframe的start方法,让它先运行起来,但是此时,包还没来,
//startrandomaccess()方法没有什么可执行的,跳到了start()方法继续阅读。
  superFrame.start();

  double exponentialMean=0.005;
  std::ofstream out("NodeChanges.txt",std::ios::app);
  	out<<exponentialMean<<" ";
  	out.flush();

//当运行到相应时间的时候,各个节点陆续有包到达了,开始正常的竞争接入随机接入过程
  Simulator::Schedule(Seconds(3.1),&PacketExponentialCome,&node1,exponentialMean);
  Simulator::Schedule(Seconds(4.5),&PacketExponentialCome,&node2,exponentialMean);
  Simulator::Schedule(Seconds(3.5),&PacketExponentialCome,&node3,exponentialMean);
  Simulator::Schedule(Seconds(3.8),&PacketExponentialCome,&node4,exponentialMean);
  Simulator::Schedule(Seconds(3.4),&PacketExponentialCome,&node5,exponentialMean);
  Simulator::Schedule(Seconds(4.6),&PacketExponentialCome,&node6,exponentialMean);
  Simulator::Schedule(Seconds(4.2),&PacketExponentialCome,&node7,exponentialMean);
  Simulator::Schedule(Seconds(4.7),&PacketExponentialCome,&node8,exponentialMean);
  Simulator::Schedule(Seconds(3.3),&PacketExponentialCome,&node9,exponentialMean);
  Simulator::Schedule(Seconds(3.9),&PacketExponentialCome,&node10,exponentialMean);


//  	  Simulator::Schedule(Seconds(3.1),&VLCNode::PacketCome,&node1,500);
//  	  Simulator::Schedule(Seconds(3.3),&VLCNode::PacketCome,&node2,600);

//  Simulator::Schedule(Seconds(2.4999),&testAddPacket,&node1,500);
//  Simulator::Schedule(Seconds(2.4999),&testAddPacket,&node2,600);
//  Simulator::Schedule(Seconds(2.5),&VLCNode::CCA,&node1);
//  Simulator::Schedule(Seconds(2.5),&VLCNode::CCA,&node2);
//预定执行到499秒的时候,执行以下delaymean方法,这个方法是输出前面统计结果的一个函数
//在最终结束之前,将所有结果输出到屏幕上
  Simulator::Schedule(Seconds(499),&DelayMean,&channel);
//预定一个停止的时间,为500秒,这里的时间是一个虚拟的时间,比真实的时间更快
  Simulator::Stop(Seconds(500));
//进入死循环,如果没有stop上面方法的约束,会一直执行下去
  Simulator::Run ();
//释放资源
  Simulator::Destroy ();
  return 0;
}

 

 类似资料: