TypeId介绍
每一个模块类都有TypeId
属性
TypeId
将每一个模块类的属性和跟踪源集合在一起,非常方便的进行属性值的设定和跟踪源的回调函数的设定
TypeId
WifiPhy::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::WifiPhy")
.SetParent<Object> ()
.SetGroupName ("Wifi")
.AddAttribute ("Frequency",
"The operating center frequency (MHz)",
UintegerValue (0),
MakeUintegerAccessor (&WifiPhy::GetFrequency,
&WifiPhy::SetFrequency),
MakeUintegerChecker<uint32_t> ())
.AddTraceSource ("PhyTxBegin",
"Trace source indicating a packet "
"has begun transmitting over the channel medium",
MakeTraceSourceAccessor (&WifiPhy::m_phyTxBeginTrace),
"ns3::Packet::TracedCallback")
;
return tid;
}
方法说明
SetParent
:设置WifiPhy
类的父类
SetGroupName
:设置WifiPhy
类所在模块组
AddAttribute
:添加属性
AddTraceSource
:添加跟踪源
AddConstructor
:添加构造器
用法
//设置属性
m_wifiphy->SetAttribute ("Frequency", TimeValue (m_frequency));
//设置属性,返回bool值说明是否成功
m_wifiphy->SetAttributeFailSafe("Frequency", DoubleValue (m_lookAroundRate));
//设置跟踪源回调
m_wifiphy->TraceConnectWithoutContext ("PhyTxBegin",
MakeCallback (&TcpSocketBase::UpdateCwnd, this));
//解除跟踪源回调
m_wifiphy->TraceDisconnectWithoutContext ("PhyTxBegin",
MakeCallback (&HierarchicalMobilityModel::ChildChanged, this));
NS3中很少使用上面的方式设置属性值的,最常用的是通过Config
类完成:
Config::Set ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Phy/$ns3::YansWifiPhy/ChannelNumber", UintegerValue(40));
*是通配符
NodeList
是一个类,每创建一个Node
对象,都会保存NodeLis
t中
DeviceList
也是一个类,每创建一个NetDevice
对象都会保存在DeviceList
中
*
表示全部,0 1 2 3这些数字表示第几个Node
对象或者NetDevice
对象
ns3::WifiNetDevice
表示对象类型
Phy
表示ns3::WifiNetDevice
这个对象的属性。这个属性在类WifiNetDevice
或者其父类里面的TypeId
中有定义
ns3::YansWifiPhy]
表示Phy
这个属性的类型值
ChannelNumber
表示ns3::YansWifiPhy
这个对象的属性。这个属性可以在类YansWifiPhy
或者其父类里面的TypeId
里面有定义
样例
NS3的Tracing系统大体分为3个部分:Tracing Sources,Tracing Sinks,以及将Tracing Sources和Tracing Sinks关联起来的方法,以basic-energy-source.cc
为例
#include "basic-energy-source.h"
#include "ns3/log.h"
#include "ns3/assert.h"
#include "ns3/double.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/simulator.h"
using namespace ns3;
class MyObject : public Object
{
public:
/**
* Register this type.
* \return The TypeId.
*/
static TypeId GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::BasicEnergySource")
.SetParent<EnergySource> ()
.SetGroupName ("Energy")
.AddConstructor<BasicEnergySource> ()
.AddTraceSource ("RemainingEnergy",
"Remaining energy at BasicEnergySource.",
MakeTraceSourceAccessor (&BasicEnergySource::m_remainingEnergyJ),
"ns3::TracedValueCallback::Double")
;
return tid;
};
TracedValue定义在basici-energy-source.h
下
TracedValue<double> m_remainingEnergyJ; // remaining energy, in Joules
回调函数=Trace Sink
void
RemainingEnergy (double oldValue, double remainingEnergy)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds ()
<< "s Current remaining energy = " << remainingEnergy << "J");
}
主函数
int
main (int argc, char *argv[])
{
Ptr<BasicEnergySource> basicSourcePtr = DynamicCast<BasicEnergySource> (sources.Get (1));
basicSourcePtr->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback (&RemainingEnergy));
}
运行结果
99.5094s Current remaining energy = 918.771J
oldValue
是改变之前的值,newValue
是改变之后的值,如果想打印oldValue
可以直接在回调函数处改变输出
实战
追踪某路由协议的控制开销
在***-routing-protocol.h
定义接收追踪和发出追踪
/// Traced Callback: transmitted packets.
TracedCallback<Ptr<const Packet> > m_txTrace; // trace
/// Traced Callback: received packets.
TracedCallback<Ptr<const Packet> > m_rxTrace; // trace
在***-routing-protocol.cc
添加TraceSource
.AddTraceSource ("Tx", "A new routing protocol packet is created and is sent or retransmitted", // trace
MakeTraceSourceAccessor (&RoutingProtocol::m_txTrace),
"ns3::Packet::TracedCallback")
.AddTraceSource ("Rx", "A new routing protocol packet is received", // trace
MakeTraceSourceAccessor (&RoutingProtocol::m_rxTrace),
"ns3::Packet::TracedCallback")
TraceCallback是在network/packet.h
定义的
这里就是个函数指针嘛,typedef下的话 取的名字叫TracedCallback
所以addTraceSource的时候TraceCallback需要绑定,用到的变量也要绑定,TX/RX是名字 也要绑定,三者绑定在一起;就可以用下面的方式调用了
typedef void (* TracedCallback) (Ptr<const Packet> packet);
在自己的仿真场景里追踪
// Tracing
Config::Connect ("/NodeList/*/$ns3::aodv::RoutingProtocol/Tx", MakeCallback (&AodvPacketTrace));
// Function for capturing overhead statistics
void
AodvPacketTrace (std::string context, Ptr<const Packet> packet)
{
std::string packetType;
std::ostringstream description;
aodv::TypeHeader tHeader;
Ptr<Packet> p = packet->Copy ();
p->RemoveHeader (tHeader);
if (!tHeader.IsValid ())
{
NS_LOG_DEBUG ("AODV message " << packet->GetUid () << " with unknown type received: " << tHeader.Get () << ". Drop");
return; // drop
}
switch (tHeader.Get ())
{
case aodv::MessageType::AODVTYPE_RREQ:
{
packetType = "RREQ";
aodv::RreqHeader rreqHeader;
p->RemoveHeader (rreqHeader);
description << "O:" << rreqHeader.GetOrigin () << " D:" << rreqHeader.GetDst () << " Hop:" << (int)rreqHeader.GetHopCount ();
countRreq++;
break;
}
case aodv::MessageType::AODVTYPE_RREP:
{
packetType = "RREP";
aodv::RrepHeader rrepHeader;
p->RemoveHeader (rrepHeader);
description << "O:" << rrepHeader.GetOrigin () << " D:" << rrepHeader.GetDst () << " Hop:" << (int)rrepHeader.GetHopCount ();
countRrep++;
break;
}
case aodv::MessageType::AODVTYPE_RERR:
{
packetType = "RERR";
countRerr++;
break;
}
case aodv::MessageType::AODVTYPE_RREP_ACK:
{
packetType = "RREP_ACK";
countRrepAck++;
break;
}
}
countAodv++;
if (countAodv==1)
{
firstAodv = Simulator::Now ();
}
lastAodv = Simulator::Now ();
uint64_t packetSize = packet->GetSize ();
bytesAodv += packetSize;
// Write packet data to file
std::ofstream out (overheadFileName.c_str (), std::ios::app);
// Time [us], Packet Type, Length [B], Description, Context
out << lastAodv.GetDouble () / 1000.0 << ","
<< packetType << ","
<< packetSize << ","
<< description.str () << "," // currently Description field is used for RREQ and RREP only
<< context << std::endl;
out.close ();
NS_LOG_INFO ("AODV stats: " << lastAodv << ", #" << countAodv << ", bytes: " << bytesAodv);
}
在routing-protocol.cc
中需要追踪的地方添加m_txTrace(packet->copy());
看过的几篇文章,写得很清楚
改变值追踪的数据追踪与采集样例
trace回调与first例子的修改