⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nsnew.htm

📁 介绍了网络仿真软件NS2的使用
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0047)http://www.isi.edu/nsnam/ns/tutorial/nsnew.html -->
<HTML><HEAD><TITLE>Marc Greis' Tutorial for the UCB/LBNL/VINT Network Simulator "ns"</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2900.3199" name=GENERATOR></HEAD>
<BODY text=#000000 bgColor=#ffffff>
<H1 align=center>VII. A new protocol for ns</H1>
<P>[<A href="http://www.isi.edu/nsnam/ns/tutorial/nsscript3.html">Previous 
section</A>] [<A href="http://www.isi.edu/nsnam/ns/tutorial/nsindex.html">Back 
to the index</A>] [<A 
href="http://www.isi.edu/nsnam/ns/tutorial/nsscript4.html">Next section</A>] 
</P>
<P>In this section I will give you an example for a new protocol that could be 
implemented in ns. You should probably become fairly familiar with ns before you 
try this yourself, and some C++ knowledge is definitely necessary. You should 
also read at least the chapters 3.1-3.3 from <A 
href="http://www.isi.edu/nsnam/ns/ns-documentation.html">"ns Notes and 
Documentation" (now renamed ns Manual)</A> to understand the interaction between 
Tcl and C++. </P>
<P>The code in this section implements some sort of simple 'ping' protocol 
(inspired by the 'ping requestor' in chapter 9.6 of the <A 
href="http://www.isi.edu/nsnam/ns/ns-documentation.html">"ns Notes and 
Documentation" (now renamed ns Manual)</A>, but fairly different). One node will 
be able to send a packet to another node which will return it immediately, so 
that the round-trip-time can be calculated. </P>
<P>I understand that the code presented here might not be the best possible 
implementation, and I am sure it can be improved, though I hope it is easy to 
understand, which is the main priority here. However, suggestions can be sent <A 
href="mailto:ns-users@isi.edu">here</A>. 
<HR>
<A name=first>
<P><STRONG>VII.1. The header file</STRONG><BR>In the new header file 'ping.h' we 
first have to declare the data structure for the new Ping packet header which is 
going to carry the relevant data. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
struct hdr_ping {
  char ret;
  double send_time;
};
</PRE></CODE></TD></TR></TBODY></TABLE>The char 'ret' is going to be set to '0' 
if the packet is on its way from the sender to the node which is being pinged, 
while it is going to be set to '1' on its way back. The double 'send_time' is a 
time stamp that is set on the packet when it is sent, and which is later used to 
calculate the round-trip-time. </P>
<P>The following piece of code declares the class 'PingAgent' as a subclass of 
the class 'Agent'. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>class PingAgent : public Agent {
 public:
  PingAgent();
  int command(int argc, const char*const* argv);
  void recv(Packet*, Handler*);
 protected:
  int off_ping_;  
};
</PRE></CODE></TD></TR></TBODY></TABLE>In the following section, I am going to 
present the C++ code which defines the constructor 'PingAgent()' and the 
functions 'command()' and 'recv()' which were redefined in this declaration. The 
int 'off_ping_' will be used to access a packet's ping header. Note that for 
variables with a local object scope usually a trailing '_' is used. </P>
<P>You can download the full header file <A 
href="http://www.isi.edu/nsnam/ns/tutorial/examples/ping.h">here</A> (I suggest 
you do that and take a quick look at it, since the code that was presented here 
isn't totally complete). </P>
<HR>
<A name=second>
<P><STRONG>VII.2. The C++ code</STRONG><BR>First the linkage between the C++ 
code and Tcl code has to be defined. It is not necessary that you fully 
understand this code, but it would help you to read the chapters 3.1-3.3 in the 
<A href="http://www.isi.edu/nsnam/ns/ns-documentation.html">"ns Manual"</A> if 
you haven't done that yet to understand it. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
static class PingHeaderClass : public PacketHeaderClass {
public:
  PingHeaderClass() : PacketHeaderClass("PacketHeader/Ping", 
                                        sizeof(hdr_ping)) {}
} class_pinghdr;


static class PingClass : public TclClass {
public:
  PingClass() : TclClass("Agent/Ping") {}
  TclObject* create(int, const char*const*) {
    return (new PingAgent());
  }
} class_ping;
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>The next piece of code is the constructor for the class 'PingAgent'. It binds 
the variables which have to be accessed both in Tcl and C++. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
PingAgent::PingAgent() : Agent(PT_PING)
{
  bind("packetSize_", &amp;size_);
  bind("off_ping_", &amp;off_ping_);
}
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>The function 'command()' is called when a Tcl command for the class 
'PingAgent' is executed. In our case that would be '$pa send' (assuming 'pa' is 
an instance of the Agent/Ping class), because we want to send ping packets from 
the Agent to another ping agent. You basically have to parse the command in the 
'command()' function, and if no match is found, you have to pass the command 
with its arguments to the 'command()' function of the base class (in this case 
'Agent::command()'). The code might look very long because it's commented 
heavily. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
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-&gt;access(off_ping_);
      // Set the 'ret' field to 0, so the receiving node knows
      // that it has to generate an echo packet
      hdr-&gt;ret = 0;
      // Store the current time in the 'send_time' field
      hdr-&gt;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));
}
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>The function 'recv()' defines the actions to be taken when a packet is 
received. If the 'ret' field is 0, a packet with the same value for the 
'send_time' field, but with the 'ret' field set to 1 has to be returned. If 
'ret' is 1, a Tcl function (which has to be defined by the user in Tcl) is 
called and processed the event (Important note to users of the ns version 2.1b2: 
'Address::instance().NodeShift_[1]' has to be replaced with 'NODESHIFT' to get 
the example to work under ns 2.1b2). 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
void PingAgent::recv(Packet* pkt, Handler*)
{
  // Access the IP header for the received packet:
  hdr_ip* hdrip = (hdr_ip*)pkt-&gt;access(off_ip_);
  // Access the Ping header for the received packet:
  hdr_ping* hdr = (hdr_ping*)pkt-&gt;access(off_ping_);
  // Is the 'ret' field = 0 (i.e. the receiving node is being pinged)?
  if (hdr-&gt;ret == 0) {
    // Send an 'echo'. First save the old packet's send_time
    double stime = hdr-&gt;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-&gt;access(off_ping_);
    // Set the 'ret' field to 1, so the receiver won't send another echo
    hdrret-&gt;ret = 1;                
    // Set the send_time field to the correct value
    hdrret-&gt;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-&gt;src_.addr_ &gt;&gt; Address::instance().NodeShift_[1],
            (Scheduler::instance().clock()-hdr-&gt;send_time) * 1000);
    Tcl&amp; tcl = Tcl::instance();     
    tcl.eval(out);                  
    // Discard the packet           
    Packet::free(pkt);              
  }                                 
}                                   
</PRE></CODE></TD></TR></TBODY></TABLE>You can download the full file <A 
href="http://www.isi.edu/nsnam/ns/tutorial/examples/ping.cc">here</A>. The most 
interesting part should be the 'tcl.eval()' function where a Tcl function 'recv' 
is called, with the id of the pinged node and the round-trip-time (in 
miliseconds) as parameters. It will be shown in <A 
href="http://www.isi.edu/nsnam/ns/tutorial/fourth">Section VII.4</A> how the 
code for this function has to be written. But first of all, some other files 
have to be edited before ns can be recompiled. </P>
<HR>
<A name=third>
<P><STRONG>VII.3. Necessary changes</STRONG><BR></P>
<P>You will have to change some things in some of the ns source files if you 
want to add a new agent, especially if it uses a new packet format. I suggest 
you always mark your changes with comments, use #ifdef, etc., so you can easily 
remove your changes or port them to new ns releases. </P>
<P>We're going to need a new packet type for the ping agent, so the first step 
is to edit the file 'packet.h'. There you can find the definitions for the 
packet protocol IDs (i.e. PT_TCP, PT_TELNET, etc.). Add a new definition for 
PT_PING there. In my edited version of packet.h, the last few lines of enum 
packet_t {} looks like the following code (it might look a bit different in 
earlier/later releases). 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>enum packet_t {
	PT_TCP,
	PT_UDP,
        ......
	// insert new packet types here
	PT_TFRC,
	PT_TFRC_ACK,
        PT_PING,    //  packet protocol ID for our ping-agent
	PT_NTYPE // This MUST be the LAST one
};

</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>You also have to edit the p_info() in the same file to include "Ping". 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
class p_info {
public:
	p_info() {
		name_[PT_TCP]= "tcp";
		name_[PT_UDP]= "udp";
                ...........
 		name_[PT_TFRC]= "tcpFriend";
		name_[PT_TFRC_ACK]= "tcpFriendCtl";

                name_[PT_PING]="Ping";

		name_[PT_NTYPE]= "undefined";
	}
        .....
 }
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>Remember that you have to do a 'make depend' before you do the 'make', 
otherwise these two files might not be recompiled. </P>
<P>The file 'tcl/lib/ns-default.tcl' has to be edited too. This is the file 
where all default values for the Tcl objects are defined. Insert the following 
line to set the default packet size for Agent/Ping. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
Agent/Ping set packetSize_ 64
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>You also have to add an entry for the new ping packets in the file 
'tcl/lib/ns-packet.tcl' in the list at the beginning of the file. It would look 
like the following piece of code. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
        { SRMEXT off_srm_ext_}
        { Ping off_ping_ }} {
set cl PacketHeader/[lindex $pair 0]
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>The last change is a change that has to be applied to the 'Makefile'. You 
have to add the file 'ping.o' to the list of object files for ns. In my version 
the last lines of the edited list look like this: 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
sessionhelper.o delaymodel.o srm-ssm.o \
srm-topo.o \
ping.o \
$(LIB_DIR)int.Vec.o $(LIB_DIR)int.RVec.o \
$(LIB_DIR)dmalloc_support.o \
</PRE></CODE></TD></TR></TBODY></TABLE></P>
<P>You should be able to recompile ns now simply by typing 'make' in the ns 
directory. If you are having any problems, please <A 
href="mailto:ns-users@isi.edu">email ns-users</A>. </P>
<HR>
<A name=fourth>
<P><STRONG>VII.4. The Tcl code</STRONG><BR>I'm not going to present the full 
code for a Tcl example for the Ping agent now. You can download a full example 
<A href="http://www.isi.edu/nsnam/ns/tutorial/examples/ping.tcl">here</A>. But I 
will show you how to write the 'recv' procedure that is called from the 'recv()' 
function in the C++ code when a ping 'echo' packet is received. 
<TABLE cellPadding=5 bgColor=#eeeeee>
  <TBODY>
  <TR>
    <TD><CODE><PRE>
Agent/Ping instproc recv {from rtt} {
        $self instvar node_
        puts "node [$node_ id] received ping answer from \
              $from with round-trip-time $rtt ms."
}
</PRE></CODE></TD></TR></TBODY></TABLE>This code should be fairly easy to 
understand. The only new thing is that it accesses the member variable 'node_' 
of the base class 'Agent' to get the node id for the node the agent is attached 
to. </P>
<P>Now you can try some experiments of your own. A very simple experiment would 
be to <STRONG>not</STRONG> set the 'ret' field in the packets to 1. You can 
probably guess what is going to happen. You can also try to add some code that 
allows the user to send ping packets with '$pa send $node' (where 'pa' is a ping 
agent and 'node' a node) without having to connect the agent 'pa' with the ping 
agent on 'node' first, though that might be a little bit more complicated than 
it sounds at first. You can also read the chapter 9.6 from the <A 
href="http://www.isi.edu/nsnam/ns/ns-documentation.html">"ns Manual"</A> to 
learn more about creating your own agents. <STRONG>Good luck</STRONG>. </P>
<HR>

<P>[<A href="http://www.isi.edu/nsnam/ns/tutorial/nsscript3.html">Previous 
section</A>] [<A href="http://www.isi.edu/nsnam/ns/tutorial/nsindex.html">Back 
to the index</A>] [<A 
href="http://www.isi.edu/nsnam/ns/tutorial/nsscript4.html">Next section</A>] 
</P>Marc Greis 
<ADDRESS><A 
href="mailto:greis@cs.uni-bonn.de">greis@cs.uni-bonn.de</A></ADDRESS></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -