提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
NS3 fifth.cc注释
最近在学NS3,tutorial的1-4代码注释都有很多帖子,但是5、6缺很少。所以贴一下查找后的代码及注释
主要参考官方tutorial的第8章。
本人缺乏相关的理论和代码基础,所有不太准确,望理解。
TCP与socket连接,可参考https://blog.csdn.net/u014618114/article/details/103242376
官方tutorial的第8章(8.3)
https://www.nsnam.org/docs/tutorial/html/tracing.html#real-example
NS3 利用Gnuplot生成拥塞窗口例子fifth.cc的png图像 可参考
https://www.cnblogs.com/zywnnblog/p/13469593.html
fifth.cc
代码如下:
/* 拥塞窗口实例
* 配置期间绑定模拟时间建立动态实体内的trace源
* fifth.cc在配置时建立了动态对象socket加入到APP中,挂起,运行时app开始调用socket把对象给系统
* 重点学习:
* 1.application重载
* 2.动态trace source如何绑定
* 3.TCP协议安装
*/
//1.头文件
#include <fstream>
#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"
//2.命名空间
using namespace ns3;
//3.日志组件
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
//因此,首先,我们创建一个套接字并对其进行跟踪连接;然后我们将此套接字传递给我们的简单应用程序的构造函数,然后我们将其安装在源节点中。
class MyApp : public Application
{
public:
MyApp (); //构造函数
virtual ~MyApp(); //析构函数
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
private:
virtual void StartApplication (void);
virtual void StopApplication (void);
void ScheduleTx (void);
void SendPacket (void);
Ptr<Socket> m_socket; //发送的socket
Address m_peer; //对端的Address,注意与IPV4Address不一样
uint32_t m_packetSize; //包长
uint32_t m_nPackets; //发包数量
DataRate m_dataRate; //数据速率
EventId m_sendEvent; //发送事件
bool m_running; //是否运行,true开始运行
uint32_t m_packetsSent; //已发送多少包
};
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}
MyApp::~MyApp()
{
m_socket = 0;
}
//初始化成员变量
//从跟踪角度来看,最重要是Ptr<Socket>套接字,我们需要在配置时提供给应用程序
//将Socket创建为一个TcpSocket,并把它传递给Set UP方法之前挂钩"CongestionWindow"跟踪源
void
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_nPackets = nPackets;
m_dataRate = dataRate;
}
//override 由模拟器自动调用 执行Socket Bind操作
void
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer); //执行与地址为m_peer的TCP建立连接所需的操作 连接后,应用程序调用SendPacket开始创建模拟事件
SendPacket ();
}
//在仿真前,会创建事件。如果事件正在执行/等待执行,IsRunning将返回true.
//这里,如果IsRunning返回true,我们取消事件,并从模拟器事件队列中删除。
//打破应用程序继续发送数据包的事件链,应用程序进入安静。之后,关闭socket,关闭TCP连接
//当m_socket=0,Socket已经在析构函数中删除了。这将移除底层Ptr<Socket>的最后一个索引。
void
MyApp::StopApplication (void)
{
m_running = false;
if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}
if (m_socket)
{
m_socket->Close ();
}
}
//创建数据包,发送
void
MyApp::SendPacket (void)
{
Ptr<Packet> packet = Create<Packet> (m_packetSize);
m_socket->Send (packet);
if (++m_packetsSent < m_nPackets) //已发送的数据包<给定的发布发包数量,就ScheduleTx ();
{
ScheduleTx ();
}
}
//如果应用程序正在运行,安排新事件,再次调用SendPacket
void
MyApp::ScheduleTx (void)
{
if (m_running)
{
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ()))); //应用层数据速率-应用层产生bit的速率
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
//实现相应的跟踪接收器 只记录当前模拟时间和拥塞窗口改变的新值。可将输出加载到图形界面gunplot/excel
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}
//追踪接收器 显示数据包被丢弃 当网络设备的网络层丢包时,触发
static void
RxDrop (Ptr<const Packet> p)
{
NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ());
}
//4.主函数
int
main (int argc, char *argv[])
{
//读取命令行参数
CommandLine cmd (__FILE__);
cmd.Parse (argc, argv);
//5.创建网络拓扑
NodeContainer nodes; //创建2节点
nodes.Create (2);
PointToPointHelper pointToPoint; //设置P2P信道属性
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
NetDeviceContainer devices; //连接信道与节点
devices = pointToPoint.Install (nodes);
//引入ErrorModel模型:RateErrorModel
Ptr<RateErrorModel> em = CreateObject<RateErrorModel> ();
em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
//上面的代码实例化了一个 RateErrorModel 对象,我们将“ErrorRate”属性设置为所需的值。然后,我们将生成的实例化 RateErrorModel 设置为点对点 NetDevice 使用的错误模型
//6.安装TCP/IP协议栈
InternetStackHelper stack;
stack.Install (nodes);
Ipv4AddressHelper address; //分配IP
address.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfaces = address.Assign (devices);
//设置socket端口
uint16_t sinkPort = 8080;
Address sinkAddress (InetSocketAddress (interfaces.GetAddress (1), sinkPort));
//实例了PacketSinkHelper,告诉ns3::TcpSocketFactory创建socket
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1)); //绑定的地址和端口
sinkApps.Start (Seconds (0.));
sinkApps.Stop (Seconds (20.));
//创建socket并连接跟踪源
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), TcpSocketFactory::GetTypeId ()); //
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
//7.安装应用程序
//实例化应用程序 手动创建安装
Ptr<MyApp> app = CreateObject<MyApp> (); //创建MyApp
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps")); //使用什么socket,地址,数据量,事件数,数据速率
nodes.Get (0)->AddApplication (app);//应用程序添加到节点中
app->SetStartTime (Seconds (1.)); //开始结束时间
app->SetStopTime (Seconds (20.));
devices.Get (1)->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&RxDrop)); //回调
Simulator::Stop (Seconds (20));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}
以上即fifth.cc