向NS2中添加协议PING

在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

posted @ 2012-03-20 12:50  always on the way  阅读(2176)  评论(0编辑  收藏  举报