用IE不会有显示的问题Firefox有的代码显示不出来;
这篇文章适合初学者,关于初学者应该参考的文档:NS by Example、NS2 Beginners Page都有很多实例可以参考。
本文通过实现一个简单的传输协议来说明如何在 ns2 中实现网络协议,当然,这个协议非常简单,但是在ns2 中实现协议(不是修改)的流程大体就是这个样子的了。我们称这个简单的协议做: simple_trans 协议,我们一步一步来,把 simple_trans 这个协议慢慢做的复杂。首先我想要明确一个概念:什么是在 ns2 中实现网络协议,不把这个问题搞明白我们都不知道自己在做什么。网路协议顾名思义网络上运行的协议,网络是由关系(无论什么关系)组成的,在这个网络上运行的规则(无论是优化网络数据传输还是共享网络信息)就叫做协议,所以我觉得把协议理解为强逻辑的规则是没有问题的。我们实现一个网络协议的前提是这个协议被设计出来,所以我们先要想好我们所要实现的协议是要用来做什么事情的;回到 ns2 , ns2 帮我们实现好了一个框架,这个框架给我们提供了数据包初始化,链路连接,数据包传递路由等功能,也就是说我们只要搭建好我们的逻辑就可以完成协议的模拟了,在 ns2 中我们通过对数据包类型、发送数据包逻辑等等进行控制。这就好比于 ns2 给我们提供了一个铁路网,火车需要的电也有了,火车不够了还可以生产,我们在 ns2 中实现协议就是要对火车进行调度,何时到站,到站后如何运行等等就是协议的内容。
下面就从我们的 simple_trans开始 说起,在这个协议里,首先我们要实现的任务非常简单,简单到什么程度了呢,简单到这个协议就是 a 节点对 b 节点说一句话:“ hi!, I’m a ”。不要笑,这也是一个协议。要在 ns2 上完成这个任务,我们首先要给 simple_trans 这个协议起个名字使得 ns2 可以发出这个协议的数据包并且认得这个协议发出的数据包,现在开始就是第一步了。
1, 在 NS_HOME/common/packet.h 的 enum packet中 加入协议数据包名称 PT_SIMPLE_TRANS_PACKET(必须的,注意不要加错地方,最好加在倒数第二的地方),在 class p_info 中加入name_[PT_SIMPLE_TRANS_PACKET] = "simple_trans_packet" (非必须的)。 Packet.cc 就不要动了。
2, 为了我们协议的独立性、好看性,我们在 NS_HOME 根目录下创建一个文件夹,我就叫他 kgn ,好在 kgn目录(也就是 NS_HOME/kgn )目录下给协议的主角: simple_trans.h&simple_trans.cc 。两个空文件没什么用,下面我们添加协议内容。
3, simple_trans.h 内容:
- #ifndef ns_simple_trans_h
- #define ns_simple_trans_h
- #include "agent.h"
- #include "tclcl.h"
- #include "packet.h"
- #include "address.h"
- #include "ip.h"
- #define PROTOCOL_DEFAULT_PORT 1023
- #define PROTOCOL_INIT_SYN 1
首先我们引用一些需要用到的头文件,然后我们定义了两个宏,第一个是我们 simple_trans 协议默认传输的端口(这方面如果有所疑问请参考这里 ),第二个是我们仅有的一条指令:同步指令(类似于 TCP 协议中三次握手的第一步,事实上我们的这个协议最终就是要实现一个简化版的三步握手)。继续看:
- struct hdr_simple_trans {
- int type;
- static int offset_;
- inline static int& offset() {
- return offset_;
- }
- inline static hdr_simple_trans * access(const Packet * p) {
- return (hdr_simple_trans*) p->access(offset_);
- }
- };
这些可以当做领导讲话的开头部分内容。就是定义一个我们协议的头所包括的内容,只有 type 这个是我定义的,其他的内容是 ns2 系统需要的。再继续:
- class simple_trans_agent : public Agent {
- public :
- simple_trans_agent();
- virtual void recv(Packet *, Handler *);
- void send_simple_msg(int type, int target);
- int get_target(){ return simple_target; }
- protected:
- int simple_target;
- int simple_port;
- int command(int argc, const char*const*argv);
- };
这里就是我们定义的负责“调度火车”的功能的类了。继承的是 agent 类,在 ns2 中,这个 agent 不可小觑,他是我们可以产生数据包、发送数据包、接收数据包的地方,包括的 target 变量就是数据包发送给的下一个目标。recv 函数会在仿真的过程中“自动”的收到网络上传输的数据包(更深层次的是经过了地址和端口过滤器);send_simple_msg 函数用来执行创建并发送数据的功能; get_target 就不用解释了(接口保护)。接下来是我们在协议制定过程中经常会用到的 timer 的定义, timer 顾名思义是一个定时器(闹钟)在到时时候会调用一个expire (超时)函数,这个被执行的超时函数的内容就是我们所感兴趣的,因为通过 timer 我们可以实现很多逻辑。
- class SYNTimer : public TimerHandler {
- public:
- SYNTimer(simple_trans_agent* t) : TimerHandler(), t_(t) {
- }
- inline virtual void expire(Event *);
- protected:
- simple_trans_agent* t_;
- };
我们只要实现 expire 函数即可, timer 的初始和使用见 simpe_trans.cc 文件:
- SYNTimer *syn_timer = new SYNTimer(this);
- syn_timer->resched(1.00);
resched 用来给“闹钟上弦”。
- void SYNTimer::expire(Event *){
- t_->send_simple_msg(PROTOCOL_INIT_SYN, t_->get_target());
- this->resched(1.00);
- }
expire 可以实现我们的“理想”了,譬如,我们到时了就发送我们的 SYN 信息给我们的目标节点(目标节点通过tcl 文件定义,下文中我们会见到)。
4, simple_trans.cc 内容:
- int hdr_simple_trans::offset_;
- static class simple_transHeaderClass : public PacketHeaderClass {
- public:
- simple_transHeaderClass() : PacketHeaderClass("PacketHeader/simple_trans",sizeof(hdr_simple_trans)) {
- bind_offset(&hdr_simple_trans::offset_);
- }