您的位置:首页 > 其它

向NS2中添加协议PING[转载]

2013-06-21 15:58 399 查看
原文地址:http://www.cnblogs.com/xyl-share-happy/archive/2012/03/20/2407732.html

------------------------------------------

在NS2中增加自己的协议模块一般分一下几个步骤:

(1) 添加协议类

(2) 定义协议分组头结构

(3) 编译代码

其实在ns3.35版本中已经有ping协议,此步骤只是为了了解ns2添加协议的一般步骤。

1、 在ping协议中,需要定义自己的控制分组,因此首先需要在ping.h头文件中定义ping的分组头结构,C++代码如下:

//在ping协议中定义自己的控制分组

struct hdr_ping {

char ret; //0:从发送者到接收者,1:从接受者到发送者

double send_time; //发送时间,为了计算RTT

};

class PingAgent : public Agent {

public:

PingAgent();

int command(int argc, const char*const* argv);

void recv(Packet*, Handler*);

protected:

int off_ping_;

};

2、ping需要被NS-2所接受并且可以在OTcl代码中使用,需要在ping.cc中定义如下代码:

static class PingHeaderClass : public PacketHeaderClass {

public:

PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping",

sizeof(hdr_ping)) {}

} class_pinghdr;

本代码实现了OTcl中的PingHead/ping类与C++中的hdr_ping绑定在一起,这样定义出的分组头为Ping。

2、 在~ns/tcl/lib/ns-packet.tcl中包含了系统中所有已实现的协议分组头名字,我们也需要在其中添加包头的名字Ping。

Foreach {

IVS

QS



Ping

}

3、 为了创建ping分组,需要定义ping的分组类型。需要修改ns/common/packet.h文件:首先在emun packet中新增包类型:PT_PING;

Enum packet_t {

PT_TCP,

PT_UDP,



PT_PING

}

然后在class p_info类的构造函数中定义新增包类型的名字:

Class p_info {

Public:

P_info {

name_[PT_TCP]=”tcp”;

……

name_[PT_PIING]="ping";



……



4、 需要从TclCL继承一个PingClass类,其构造函数通过调用基类的构造函数“TclClass(”Agent/Ping”)”指定其对应的OTcl对象为Agent/Ping,这实际是做了登记工作,在ping.cc中定义:

static class PingClass : public TclClass {

public:

PingClass() : TclClass("Agent/Ping") {}

TclObject* create(int, const char*const*) {

return (new PingAgent());

}

} class_ping;

OTcl代码:

set p0 [new Agent/Ping]

$ns attach-agent $n0 $p0

当执行set p0 [new Agent/Ping]时,就会调用父类的构造函数(init方法),父类SplitObject调用create-shadow方法来登记OTcl对象p0和被创建的C++对象class_ping的关系。根据登记关系去调用TclObject* create(int, const char*const*)创建并返回对象指针:return (new PingAgent());

5、 需要在PingAgent的构造函数中,需要将新创建的分组类型传递给Agent类的构造函数,因为PingAgent父类的构造函数中就需要定制分组类型作为参数。在PingAgent构造函数中实现C++和OTcl之间成员变量的绑定。

PingAgent::PingAgent() : Agent(PT_PING)

{

bind("packetSize_", &size_);

bind("off_ping_", &off_ping_);

}

变量绑定后,Agent/Ping类对象p0的成员变量packetSize_和off_ping_的变量在任何时候都和C++对象的成员变量保持一致。为了给这些变量初始化,需要在~ns/tcl/lib/ns-default.tcl中添加以下代码:

Agent/Ping set packetSize 0

Agent/Ping set off_ping_ 0

ns-default.tcl这个文件是在Tcl脚本运行之前被执行的,所以在创建对象并在绑定变量时,变量已经进行了初始化。

6、当执行

$ns at 0.2 "$p0 send"

C++对象的指针根据过程函数名去调用command函数,如下:

int PingAgent::command(int argc, const char*const* argv)

{

if (argc == 2) {

if (strcmp(argv[1], "send") == 0) {

// Create a new packet

Packet* pkt = allocpkt();

// Access the Ping header for the new packet:

hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_);

// Set the 'ret' field to 0, so the receiving node knows

// that it has to generate an echo packet

hdr->ret = 0;

// Store the current time in the 'send_time' field

hdr->send_time = Scheduler::instance().clock();

// Send the packet

send(pkt, 0);

// return TCL_OK, so the calling function knows that the

// command has been processed

return (TCL_OK);

}

}

// If the command hasn't been processed by PingAgent()::command,

// call the command() function for the base class

return (Agent::command(argc, argv));

}

6、 完成ping协议的定义和实现后,把ping.hh和ping.cc放在~ns/ping下,然后重新编译NS-2,把ping协议嵌入到NS-2代码中去,我们需要修改~ns/Makefile文件。

在Makefile的OBJ_CC中,增加以下代码:ping/ping.o

在ns目录下:make clean和make,完成编译。

7、 ping.cc中的recv函数代码如下:

void PingAgent::recv(Packet* pkt, Handler*)

{

// Access the IP header for the received packet:

hdr_ip* hdrip = (hdr_ip*)pkt->access(off_ip_);

// Access the Ping header for the received packet:

hdr_ping* hdr = (hdr_ping*)pkt->access(off_ping_);

// Is the 'ret' field = 0 (i.e. the receiving node is being pinged)?

if (hdr->ret == 0) {

// Send an 'echo'. First save the old packet's send_time

double stime = hdr->send_time;

// Discard the packet

Packet::free(pkt);

// Create a new packet

Packet* pktret = allocpkt();

// Access the Ping header for the new packet:

hdr_ping* hdrret = (hdr_ping*)pktret->access(off_ping_);

// Set the 'ret' field to 1, so the receiver won't send another echo

hdrret->ret = 1;

// Set the send_time field to the correct value

hdrret->send_time = stime;

// Send the packet

send(pktret, 0);

} else {

// A packet was received. Use tcl.eval to call the Tcl

// interpreter with the ping results.

// Note: In the Tcl code, a procedure 'Agent/Ping recv {from rtt}'

// has to be defined which allows the user to react to the ping

// result.

char out[100];

// Prepare the output to the Tcl interpreter. Calculate the round

// trip time

sprintf(out, "%s recv %d %3.1f", name(),

hdrip->src_ >> Address::instance().NodeShift_[1],

(Scheduler::instance().clock()-hdr->send_time) * 1000);

Tcl& tcl = Tcl::instance();

tcl.eval(out);

// Discard the packet

Packet::free(pkt);

}

}

8、TCL测试脚本如下:

#Create a simulator object

set ns [new Simulator]

#Open a trace file

set nf [open out.nam w]

$ns namtrace-all $nf

#Define a 'finish' procedure

proc finish {} {

global ns nf

$ns flush-trace

close $nf

exec nam out.nam &

exit 0

}

#Create three nodes

set n0 [$ns node]

set n1 [$ns node]

set n2 [$ns node]

#Connect the nodes with two links

$ns duplex-link $n0 $n1 1Mb 10ms DropTail

$ns duplex-link $n1 $n2 1Mb 10ms DropTail

#Define a 'recv' function for the class 'Agent/Ping'

Agent/Ping instproc recv {from rtt} {

$self instvar node_

puts "node [$node_ id] received ping answer from \

$from with round-trip-time $rtt ms."

}

#Create two ping agents and attach them to the nodes n0 and n2

set p0 [new Agent/Ping]

$ns attach-agent $n0 $p0

set p1 [new Agent/Ping]

$ns attach-agent $n2 $p1

#Connect the two agents

$ns connect $p0 $p1

#Schedule events

$ns at 0.2 "$p0 send"

$ns at 0.4 "$p1 send"

$ns at 0.6 "$p0 send"

$ns at 0.6 "$p1 send"

$ns at 1.0 "finish"

#Run the simulation

$ns run
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: