首页 > 其他分享 >ns-3_ Day2

ns-3_ Day2

时间:2022-12-19 10:55:50浏览次数:45  
标签:include ns3 Day2 ns limit NS Ptr

ns-3的代码设计

ns-3的核心是时间调度和网络模拟的支持,在工程技术上有很多重要的设计值得了解。

核心模块

ns-3的内核指的就是 src/core/下的代码,而基于core定义的network模块给出了最基本的单元定义如packet。围绕这两个模块,可以将ns-3的结构描述为:
image.png

随机数

随机数生成器RNG的功能:

  1. 提供一个随机数序列(循环序列);
  2. 可以被分隔成几个相互独立的数据流。

我们总是希望一个RNG能提供一个非常长的循环序列,并有效地分配每一个数据流。
ns-3使用 MRG32k3a 生成器,保证足够的循环长度以及数据流数量。
一个生成随机数的例子:

#include "ns3/simulator.h"
#include "ns3/nstime.h"
#include "ns3/command-line.h"
#include "ns3/rng-seed-manager.h"
#include "ns3/random-vatiable-stream.h"
#include <iostream>

using namespace ns3;

int main(int argc, char *argv[])
{
	CommandLine cmd;
	cmd.Parse(argc, argv);
	double min = 0.0;
	double max = 10.0;
	
	// 改变种子后会得到不同的随机数
	// 如果不改变种子同时运行多组实验,可以通过SetRun()来设置组数保证实验的独立性
	RngSeedManager::SetSeed(1);
	Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable>();
	uv->SetAttribute("Min", DoubleValue(min));
	uv->SetAttribute("Max", DoubleValue(max));
	std::out << uv->GetValue() << std::endl;
	return 0;
}

回调机制

针对静态函数

//...
static double
CbOne(double a, double b)
{
	std::out << "invoke cbOne a=" << ", b=" << b << std::endl;
	return a;
}
int main(int argc, char* argv[])
{
	// 声明了一个叫“one”的回调,指定了返回值和两个参数都是double
	// 绑定CbOne为回调函数
	Callback<double, double, double> one = MakeCallback(&CbOne);

	// ...
	NS_ASSERT(!one.IsNull());
	double retOne = one(10.1, 11.2);
}

针对类成员函数

class MyCb{
public:
	int CbTwo(double a){
		std::out << "invoke cbTwo a=" << a << std::endl;
	}
	return -5;
}

MyCb cb;
Callback<int, double> two = MakeCallback(&MyCb::CbTwo, &cb);
NS_ASSERT(!two.IsNull());
int retTwo = two(10.0);

构建Null回调的方法

MakeNullCallback<int, double>();

Attribute系统

从下面的例子及注释中可以看清Attribute的用法

#include "ns3/log.h"
#include "ns3/command-line.h"
#include "ns3/ptr.h"
#include "ns3/config.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/node.h"
#include "ns3/queue.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/point-to-point-net-device.h"

using namespace ns3;

int main(int argc, char *argv[])
{
	LogComponentEnable("AttributeValueSample", LOG_LEVEL_INFO);

	// 1. 设置默认值
	Config::SetDefault("ns3::DropTailQueue::MaxPackets", StringValue("80"));
	Config::SetDefault("ns3::DropTailQueue::MaxPackets", UintegerValue("80"));

	CommandLine cmd;
	cmd.Parse(argc, argv);

	// 这里体现了ns-3使用模板创建对象的方法 CreateObject
	// Ptr是ns-3提供的计数指针
	Ptr<Node> n0 = CreateObject<Node>();
	Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice>();
	n0->AddDevice(net0);

	// 为node分配一个packet队列,它从尾部开始丢弃packet
	Ptr<Queue> q = CreateObject<DropTailQueue>();
	net0->SetQueue(q);

	// ptr是一个指针变量,然后把net0的TxQueue赋值给ptr
	PointerValue ptr;
	// 2. 通过指针获取属性值
	net0->GetAttribute("TxQueue", ptr);
	Ptr<Queue> txQueue = ptr.Get<Queue>();

	Ptr<DropTailQueue> dtq = txQueue->GetQueue<DropTailQueue>();
	NS_ASSERT(dtq);

	UintegerValue limit;
	dtq->GetAttribute("MaxPackets", limit);
	NS_LOG_INFO("1. dtq limit: " << limit.Get() << " packets");

	txQueue->GetAttribute("MaxPackets", limit);
	NS_LOG_INFO("2. txQueue limit: " << limit.Get() << " packets");

	txQueue->SetAttribute("MaxPackets", UintegerValue(60));
	txQueue->GetAttribute("MaxPackets", limit);
	NS_LOG_INFO("3. txQueue limit changed: " << limit.Get() << " packets");

	Config::Set("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue(25));
	txQueue->GetAttribute("MaxPackets", limit);
	NS_LOG_INFO("4. txQueue limit changed through namespace: " << limit.Get() << " packets");

	Config::Set("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue(15));
	txQueue->GetAttribute("MaxPackets", limit);
	NS_LOG_INFO("5. txQueue limit changed through wildcarded namespace: " << limit.Get() << " packets");

	Simulator::Destory();
}

除了上述两个方法,还有添加属性条目的方法:AddAttribute()
对于类TcpSocket的一个成员变量 uint32_tm_cWnd,假设使用TCP模块时想要试用元数据获取或设置该变量的值,如果ns-3还没有提供这个变量,那么用户可以在元数据系统中添加如下声明:

ptr->AddAttribute("Congestion window", "Tcp congestion window (bytes)",
				Uintergevalue(1),
				MakeUintegerAccessor(&TcpSocket::m_cWnd),
				MakeUintegerChecker<uint16_t>())

Tracing系统

拆解一个Tracing系统,其组成可以理解为:TracingSource、TracingSink以及关联它们的方法。
通过一个例子了解:

#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include <iostream>

using namespace ns3;

//	Tracing系统和Attribute系统密切相关,
//	所以每一个要trace的数据都必须属于一个特定的类。
class MyObject : public Object
{
public:
	static TypeId GetTypeId(void)
	{
		static TypeId tid = TypeId("MyObject")
			.SetParent(Object::GetTypeId())
			.AddConstructor<MyObject>()
			.AddTraceSourceAccessor(&MyObject::m_myInt);
		//	此处的m_myInt被确定为一个TracingSource
		return tid;
	}
	MyObject(){}
	TraceValue<uint32_t> m_myInt;
}
//	函数IntTrace就是TraceSink
void IntTrace(int oldValue, int newValue)
{
	std::out << "Traced " << oldValue << " to " << newValue << std::endl;
}

int main(int argc, char *argv[])
{
	Ptr<MyObject> myObject = CreateObject<MyObject>();
	//	这个函数将Source和Sink关联起来
	//	当myObject.m_myInt改变时,IntTrace才会被调用
	myObject->TraceConnectWithoutContext("MyInteger", MakeCallback(&IntTrace));
	myObject->m_myInt = 1234;
}

但是TraceConnectWithoutContext这样的函数很少被使用。
通常我们使用一个被叫作“Config Path”的子系统。

如何关联TraceSource和TraceSink

下面演示了如何使用Config关联TraceSource和TraceSink

using namespace std;

//	这个函数就是TraceSink
void CourseChange(string context, Ptr<const MobilityModel> model)
{
	Vector posision = model->GetPosition();
	NS_LOG_UNCOND(context << " x = " << position.x << " y = " << position.y);
}

//	...

ostringstream  oss;
//	类MobilityModel的属性CourseChange是TraceSource
oss << "/NodeList/" << wifiStaNodes.Get(nWifi-1)->GetId() << "/$ns3::MobilityModel/CourseChange";
Config::Connect(oss.str(), MakeCallback(&CourseChange));

oss.str()其实就是“ConfigPath”,起到了类似绑定的作用,每当MobilityModel的位置/速度的值变了就会进行trace。

如何确定TraceSource

所有可用的TraceSource在文档: ns-3: All TraceSources

如何确定TraceSink

其实就是定义一个函数并将其设置为回调。
该函数的确定步骤如下:

  1. 返回值为 void
  2. 参数列表的参数类型是 TraceSource 的变量类型
  3. 要是用 Config::Connect,那么参数列表的第一个参数还得加一个字符串参数

标签:include,ns3,Day2,ns,limit,NS,Ptr
From: https://www.cnblogs.com/leewaytang/p/16991633.html

相关文章