新增或修改NS2的核心模块
- 格式:doc
- 大小:119.50 KB
- 文档页数:8
分类:网络模拟器(NS2)2013-07-04 13:20 183人阅读评论(4) 收藏举报NS2最近,自己在做ns2的开发,主要就是为了科研啦,其他基本上不会涉及这个网络仿真平台。
废话不多说了,开始介绍这个NS2开发平台的搭建:1、安装JDK。
JDK的版本找个最新的就可以了,安装是采用默认目录,安装好配置下环境变量:path,classpath。
这一步基本没什么问题的;2、需要安装netbeans。
建议选择一个完整版的,其中包含了C++开发的插件。
安装过程中依据向导选择就好了,最后都能完成安装的;3、安装cygwin。
这里我采用了一个完整版的cygwin,读者可以根据自己需要采用各自的版本,不受限制的,只要第4步的NS2能安装上即可。
有关cygwin的安装请参考柯志恒的网站(在google中输入ns2就能找到,一般在第二个),这里就不细讲了。
4、安装NS2。
这一步很多时候会存在问题,有关安装的问题可以参考NS2的官网,在此不再赘述。
5、建立一个NS2项目,这是关键,前面的平台搭建好了,该怎么开发NS2项目呢?接下来细细道来:首先,打开“文件”——>“新建项目”,选择类别中的“C/C++”,在右边项目选框中选择“基于现有源代码的C/C++项目”,点击下一步;其次,点击“浏览”按钮,选择ns-2.xx所在的位置,点击确定。
其他部分保持默认,单击完成,此时就已经创建了已有源码的项目了,需要编译一段时间,耐心等待。
6、编译完成之后,就可以在已有的NS2项目中建立或修改项目了。
如果是建立项目,则建议在ns-2.xx下建立一个自己的项目文件夹,然后将写的C++或脚本放入其中;如果是修改原项目,则不需要了。
7、建立或修改完项目后,需需要进行“生成”或“清除并生成”,前一个只编译修改过的文件,后一个则先清除已有编译文件,并重新全部编译。
建议前一种。
8、如果建立的项目没问题,则可编写脚本进行仿真了。
如果有问题则需要进行错误调试。
Linux下的NS2安装+LEACH及错误修改一、安装前的预备说明为了方便实验和利用,采纳的实在虚拟机上安装,安装和配置进程与实体无异。
环境:+预备:在安装编译之前确保Linux中已经安装了gcc++编译工具,和XFree86-devel and XFree86-libs两个组件。
别离为:X 软件开发KDE桌面环境,能够在添加删除程序中进行安装。
二、安装进程1. 本实验安装环境:完全安装的RedHat 操作系统,安装包。
2. 到官方下载网址下载NS2安装软件包以root登录RH9,在/home下成立ns2文件夹,将放在该文件夹下,在终端运行cd /home/ns2,利用解压命令tar xvfz ,即生成/home/ns2/ .4. 修改/home/ns2/ 中的第73行,将NULL改成0.5. 在/home/ns2/ 下运行。
/install6. 依照安装终止后结尾处的提示,将某些途径复制下来,或直接依照以下修改(能够对照提示明白得):7. 修改/root/.bashrc(注意该文件为隐藏文件),在该文件末尾加上以下三句话:exportPATH=$PATH:/home/ns2/bin:/home/ns2/ /:/home/ns2/:/home/ns2/:/home/ns2/lib exportTCL_LIBRARY=$TCL_LIBRARY:/home/ns2/在root途径下输入命令:source .bash_profile进行环境变量的更新8.这时,假设是以上设置正确,直接运行ns会显现%,或能够运行软件自带的例子,在/home/ns2/ns-tutorial/examples下运行nsLEACH协议的安装预备:获取LEACH的源码文件:1.进入到目录/home/ns2/下解压LEACH协议源文件[root@localhost root]# cd /home/ns2/[root@localhost ]# tar -xzcf ./2.修改MakeFile文件1)添加-DMIT_uAMPS到DEFINE中DEFINE = -DTCP_DELAY_BIND_ALL.......-DMIT_uAMPS2)添加-I./mit/rca -I./mit/uAMPS到INCLUDE中INCLUDES = \-I./diffusion3/filter_core -I./asim/ -I./qs \-I./diffserv -I./satellite \-I./wpan \-I./mit/rca -I./mit/uAMPS \3)添加以下代码在gaf/ \之前mit/rca/ mit/rca/ \mit/rca/ mit/rca/ \mac/ mac/ mit/uAMPS/ \注:添加进程中利用TAB键代替空格。
一、NS2 程序简介对于如何验证网络协议的正确性和进行相关性能测试,人们提出了很多方法,目前最广泛使用的方法就是通过虚拟环境进行模拟仿真。
NS-2 是进行网络仿真最流行的软件,已广泛被科研院所和各大高校用于进行网络分析、研究和教学。
它支持众多的协议,并提供了丰富的测试脚本。
NS-2 全称是Network Simulator Version 2。
它是面向对象的,离散事件驱动的网络环境模拟器,主要用于解决网络研究方面的问题。
NS-2 提供在无线或有线网络上,TCP、路由、多播等多种协议的模拟。
NS-2最早来源与1989年的Real Network Simulator 项目,经过多年的发展之后,于1995年得到施乐公司(Xerox)的支持,加入VINT 项目。
NS 一直以来都在吸收全世界各地研究者的成果,包括UCB、CMU 等大学和SUN等公司的无线网络方面的代码。
NS-2 由两种编程语言,OTCL(具有面向对象特性的TCL 脚本程序设计语言)和C++实现。
之所以使用两种编程语言,是因为模拟器有两方面的事情需要做。
一方面,具体协议的模拟和实现,需要一种程序设计语言,能够高效率的处理字节(Byte),报头(Packet Header)等信息,能够应用合适的算法在大量的数据集合上进行操作。
为了实现这个任务,程序内部模块的运行速度(run-time speed)是非常重要的,而运行模拟环境的时间、寻找和修复bug 的时间,重新编译和运行的时间(run-around time)不是很重要。
这种情况下,C++语言是非常合适的。
另一方面,许多网络中的研究工作都围绕着网络组件和环境的具体参数的设置和改变而进行的,需要在短时间内快速的开发和模拟出所需要的网络环境(scenarios),并且方便修改和发现、修复程序中的Bug。
在这种任务中,网络环境布置的时间就显得很重要了,因为模拟环境的建立和参数信息的配置只需要运行一次。
NS2中SMAC修改先调用SMAC的构造函数,里面有mhGene_.sched(t),经过t秒后超时,超时后调用handleGeneTimer()函数。
setMySched(): 把MAC state设为0,numSched_设为1,把调度表的txSync设为1,说明要发送同步帧。
如果没有收到同步帧,就要自己建立调度表,调度表的状态加1,并且把调度表的同步节点设置为当前节点。
经过listenTime_+index*10的时间后CounterTimer超时,调用handleCounterTimer()函数。
handleCounterTimer():首先要保证该调度表的节点数大于0,如果改CounterTimer的value是sleepTime_的话,说明现在睡眠已经结束了。
如果现在radioState不能发送或接收的话,给CounterTimer设置ListenTime_的时间,超时后调用handleCounterTimer()函数。
如果MAC state可以发送并且该调度表的txSync_为1的话,把syncSched_设置为该调度表的id,同时开始竞争退避,当计数器减到0的时候调用handleCSTimer()函数。
adaptiveListen(): 如果节点处于睡眠状态,就把节点唤醒,总之要保证节点是醒着的。
然后判断节点是否有数据要发送,如果有数据发送的话调用checkToSend()这个函数发送数据。
同时设置了adapTime,节点在adapTime这段时间后定时器超时,调用handleAdaptiveListenTimer()函数。
如果是收到同步帧的话,经过同步帧中的sleepTime来设置CounterTimer,并且经过sleepTime后调用handleCounterTimer()函数。
然后把我的同步节点设为收到的同步帧中指示的同步节点。
把0号调度表的节点数增加1,0号调度表的同步节点设置为收到的同步帧中指示的同步节点,并且调度表的状态数加1.然后把发同步帧的节点加到我的同步列表中。
ns2的基本功能和用法。
NS2是一款广泛使用的离散事件网络仿真器,它可以用来模拟网络协议、网络拓扑结构、传输层协议等各种网络方面的问题。
在本文中,我们将会详细介绍NS2的基本功能和用法,让您了解如何使用这个强大的工具来开展网络仿真和探索。
第一部分:NS2的简介NS2全称Network Simulator 2,是一款免费且开源的网络仿真平台,它可以运行于Linux和Windows操作系统。
NS2是C++编写的,它是由一个模块化的体系结构构建而成的。
NS2可以帮助你模拟和测试各种网络协议和技术,包括但不限于TCP/IP、WiFi、无线通信、移动通信、卫星通信等。
NS2的基本组成部分包括:- OTcl:OTcl是一个面向对象的Tcl解释器,它被用来编写NS2的脚本文件。
它可以帮助您表示仿真模型以及控制仿真场景和参数。
- C++代码:NS2的模拟核心是由C++编写的,它包含了底层的网络协议处理逻辑和数据结构。
- Trace:NS2的Trace模块可以记录仿真过程中所有的事件和消息交换。
我们可以通过Trace来分析仿真结果,并对仿真场景进行可视化。
总结NS2是一个开源且强大的网络仿真器,它的核心部分是由C++编写而成的。
NS2可以帮助您模拟和测试各种网络协议和技术,并提供一个强大的OTcl 脚本语言来控制和配置仿真模型。
第二部分:NS2的基本功能NS2提供了很多强大的功能,如下所示:1. 拓扑结构模拟NS2可以帮助我们模拟各种网络拓扑结构,例如星型、树形结构、层次结构等。
通过定义节点、连接和协议,我们可以很容易地构建复杂的拓扑结构,并进行仿真和测试。
2. 参数设置和控制通过OTcl脚本,我们可以轻松地配置和控制仿真模型。
我们可以设置各种参数,例如发送速率、仿真持续时间、节点位置等等。
此外,我们还可以通过设置事件触发器来控制仿真场景的流程。
3. 模拟协议NS2可以帮助我们模拟各种协议,例如TCP、UDP、ICMP等。
浅析Opnet,Ns2,Matlab网络仿真工具【摘要】网络仿真可以有效提高网络规划和设计的可靠性和准确性,明显地降低网络投资风险,减少不必要的投资浪费。
本文就常见的三种网络仿真工具(OPNET、NS2及MATLAB),从它们的基本情况及特点进行了分析。
【关键字】网络仿真;OPNET;NS2;MATLAB引言随着网络结构和规模越来越复杂化以及网络的应用越来越多样化,单纯地依靠经验进行网络的规划和设计、网络设备的研发以及网络协议的开发,已经不能适应网络的发展,因而急需一种科学的手段来反映和预测网络的性能,网络仿真技术应运而生。
网络仿真可以有效提高网络规划和设计的可靠性和准确性,明显地降低网络投资风险,减少不必要的投资浪费。
各种网络仿真工具在此背景下应运而生。
本文就常见的三种网络仿真工具(OPNET、NS2及MATLAB),从它们的基本情况及特点进行了分析。
基本情况及特点分析1.OPNETOPNET公司最初只有一种产品OPNET Modeler,到目前已经拥有Modeler、ITGuru、SPGuru、WDMGuru、ODK等一系列产品。
对于网络的设计和管理,一般分为3个阶段:第1阶段为设计阶段,包括网络拓扑结构的设计,协议的设计和配置以及网络中设备的设计和选择;第2阶段为发布阶段,设计出的网络能够具有一定性能,如吞吐率、响应时间等等;第3阶段为实际运营中的故障诊断、排错和升级优化。
而OPNET公司的整个产品线正好能面向网络研发的不同阶段,即可以作网络的设计,也可以作为发布网络性能的依据,还可以作为已投入运营的网络的优化和故障诊断工具。
OPNET公司也是当前业界智能化网络管理分析解决方案的主要提供商。
OPNET的主要特点:层次化的网络模型。
使用无限嵌套的子网来建立复杂的网络拓扑结构。
简单明了的建模方法。
Modeler建模过程分为3个层次:过程(process)层次、节点(Node)层次以及网络(Network)层次。
序号项目名称项目概述1指纹身份识别认证系统指纹份识别系统采用指纹识别技术作为身份鉴别手段,配合功能强大的网络化系统管理平台,是一种高精度、智能化、网络化的防止非授权人员进入的认证系统,指纹识别技术是目前最方便、可靠、非侵害和价格便宜的解决方案。
指纹识别作为识别技术有着悠久的历史,这种技术通过分析指纹的全局特征和局部特征,从指纹中抽取的特征值可以非常的详尽以便可靠地通过指纹来确认一个人的身份。
平均每个指纹都有几个独一无二可测量的特征点,每个特征点都有大约七个特征,我们的十个手指产生最少4900个独立可测量的特征--这足够来确认指纹识别是否是一个更加可靠的鉴别方式。
2网络入侵异常检测系统实现一个基于分布式通信平台的入侵检测系统,将异常检测等入侵检测模块按网络层次分布到网络中的多个节点上去,提高系统的运行性能,加大系统所能监控的网络大小。
包括网络层异常检测技术,应用层异常检测技术,分布式入侵的攻击源反向追踪技术3匿名认证系统匿名认证研究,研究认证中用户身份信息的隐私保护,设计一种以用户属性为认证基点,既能体现隐私保护又能满足认证需求,同时具备追踪用户真实身份能力的隐私认证方法。
这一阶段解决用户申请服务时,服务方认证用户的匿名问题;4研究生学论文跟踪管理信息系统开发一套研究生学位论文预审、送审、跟踪、结果反馈的信息系统5图像缩略图处理FPGA设计在充分理解现存各种缩略图处理算法的基础上,设计一个适合FPGA的缩略图压缩系统。
6图像分类处理FPGA设计在充分理解现存各种图像分类处理算法的基础上,设计一个适合FPGA的图像分类系统。
7人像漫画处理8基于嵌入式的智能家居系统9高质量互联网社区识别技术社区是Web 最有价值的结构特征之一。
社区识别是Web 领域的热点研究课题,在许多实际应用中起着重要的作用。
现有的算法仅通过链接分析识别社区,求解质量偏低,不能满足实际应用的需求。
我们通过前期大量研究和分析工作得出结论:仅通过链接分析不可能精确识别社区。
NS2添加协议步骤step 1:比如我们新建的协议名字就叫做protoname,以ns2.27平台为例,我们在ns2.27目录下建立一个protoname目录。
此目录包含protoname.h,,protoname_pkt.h,protoname_rtable.h,protoname_五个文件。
其中五个文件的具体功能和作用如下:(1)protoname.h 定义必要的计时器和路由代理(2) 执行计时器、路由代理和Tcl文件(3)protoname_pkt.h 声明protoname路由协议需要在无线自组网节点交换的数据包(4)protoname_rtable.h 声明我们自己的路由选择表(5)protoname_ 执行路由选择表step 2:相应文件的代码(1)protoname.h#ifndef __protoname_h__#define __protoname_h__// 下面包含一些需要的头文件#include "protoname_pkt.h" //数据包报头#include "protoname_rtable.h"#include <agent.h> //代理基本类#include <packet.h> //数据包类#include <trace.h> //跟踪类,用于在跟踪文件里记录输出的仿真结果#include <timer-handler.h> //计时器基本类,创建我们自定义的计时器#include <random.h> //随机类,用于产生伪随机数#include <classifier-port.h> //端口分类器类,用于淘汰向上层传输的数据包#include <mobilenode.h>#include "arp.h"#include "ll.h"#include "mac.h"#include "ip.h"#include "delay.h"#define CURRENT_TIME Scheduler::instance().clock() //定义了一个用于得到当前仿真时间的宏//通过一个调度类的实例完成#define JITTER (Random::uniform()*0.5) //在0-0.5之间取随机数作为发送数据的延迟时间class Protoname; // forward declaration/* Timers */ //自定义计时器发送定时的控制包class Protoname_PktTimer : public TimerHandler {public:Protoname_PktTimer(Protoname* agent) : TimerHandler() {agent_ = agent;}protected:Protoname* agent_;virtual void expire(Event* e);};/* Agent */ //定义Protoname 类class Protoname : public Agent {/* Friends */friend class Protoname_PktTimer;/* Private members */ //封装了自身的地址、内状态、路由表、可变的Tcl//以及一个负责指定输出数量的计数器nsaddr_t ra_addr_;//protoname_state state_;protoname_rtable rtable_; //协议的路由表对象?int accesible_var_; //用来读取Tcl代码或脚本语言u_int8_t seq_num_;protected:MobileNode* node_;PortClassifier* dmux_; // For passing packets up to agents.端口分类器Trace* logtarget_; // For logging.跟踪器Protoname_PktTimer pkt_timer_; // Timer for sending packets.自定义计时器//内部属性inline nsaddr_t& ra_addr() { return ra_addr_; }//inline protoname_state& state() { return state_; }inline int& accessible_var() { return accesible_var_; }void forward_data(Packet*); //数据包被正确传输的目的地void recv_protoname_pkt(Packet*);void send_protoname_pkt();void reset_protoname_pkt_timer();public:Protoname(nsaddr_t);int command(int, const char*const*);void recv(Packet*, Handler*);//void mac_failed(Packet*);};#endif(2)#include "protoname.h"#include "protoname_pkt.h"#include <random.h>#include <cmu-trace.h>#include <iostream>int hdr_protoname_pkt::offset_;//注册包头static class ProtonameHeaderClass : public PacketHeaderClass {public:ProtonameHeaderClass() : PacketHeaderClass("PacketHeader/Protoname", sizeof(hdr_protoname_pkt)) {bind_offset(&hdr_protoname_pkt::offset_);}} class_rtProtoProtoname_hdr;//注册协议类名使能在Tcl中创建对象static class ProtonameClass : public TclClass {public:ProtonameClass() : TclClass("Agent/Protoname") {}TclObject* create(int argc, const char*const* argv) {assert(argc == 5);return (new Protoname((nsaddr_t) Address::instance().str2addr(argv[4])));}} class_rtProtoProtoname;voidProtoname_PktTimer::expire(Event* e) {agent_->send_protoname_pkt();agent_->reset_protoname_pkt_timer();}Protoname::Protoname(nsaddr_t id) : Agent(PT_PROTONAME), pkt_timer_(this) { bind_bool("accesible_var_", &accesible_var_);ra_addr_ = id;node_ = (MobileNode*)Node::get_node_by_address(id);}intProtoname::command(int argc, const char*const* argv) {if (argc == 2) {if (strcasecmp(argv[1], "start") == 0) {pkt_timer_.resched(0.0);return TCL_OK;}else if (strcasecmp(argv[1], "print_rtable") == 0) {if (logtarget_ != 0) {sprintf(logtarget_->pt_->buffer(), "P %f _%d_ Routing Table", CURRENT_TIME, ra_addr());logtarget_->pt_->dump();rtable_.print(logtarget_);}else {fprintf(stdout, "%f _%d_ If you want to print this routing table ""you must create a trace file in your tcl script", CURRENT_TIME, ra_addr());}return TCL_OK;}}else if (argc == 3) {// Obtains corresponding dmux to carry packets to upper layersif (strcmp(argv[1], "port-dmux") == 0) {dmux_ = (PortClassifier*)TclObject::lookup(argv[2]);if (dmux_ == 0) {fprintf(stderr, "%s: %s lookup of %s failed\n", __FILE__, argv[1], argv[2]);return TCL_ERROR;}return TCL_OK;}// Obtains corresponding tracerelse if (strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) {logtarget_ = (Trace*)TclObject::lookup(argv[2]);if (logtarget_ == 0)return TCL_ERROR;return TCL_OK;}}// Pass the command to the base classreturn Agent::command(argc, argv);}voidProtoname::recv(Packet* p, Handler* h) {struct hdr_cmn* ch = HDR_CMN(p);struct hdr_ip* ih = HDR_IP(p);if (ih->saddr() == ra_addr()) {// If there exists a loop, must drop the packetif (ch->num_forwards() > 0) {drop(p, DROP_RTR_ROUTE_LOOP);return;}// else if this is a packet I am originating, must add IP headerelse if (ch->num_forwards() == 0)ch->size() += IP_HDR_LEN;}// If it is a protoname packet, must process itif (ch->ptype() == PT_PROTONAME)recv_protoname_pkt(p);// Otherwise, must forward the packet (unless TTL has reached zero) else {ih->ttl_--;if (ih->ttl_ == 0) {drop(p, DROP_RTR_TTL);return;}forward_data(p);}}voidProtoname::recv_protoname_pkt(Packet* p) {struct hdr_ip* ih = HDR_IP(p);struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);// All routing messages are sent from and to port RT_PORT,// so we check it.assert(ih->sport() == RT_PORT);assert(ih->dport() == RT_PORT);/* ... processing of protoname packet ... */// Release resourcesPacket::free(p);}voidProtoname::send_protoname_pkt() {Packet* p = allocpkt();struct hdr_cmn* ch = HDR_CMN(p);struct hdr_ip* ih = HDR_IP(p);struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);ph->pkt_src() = ra_addr();ph->pkt_len() = 7;ph->pkt_seq_num() = seq_num_++;ch->ptype() = PT_PROTONAME;ch->direction() = hdr_cmn::DOWN;ch->size() = IP_HDR_LEN + ph->pkt_len();ch->error() = 0;ch->next_hop() = IP_BROADCAST;ch->addr_type() = NS_AF_INET;ih->saddr() = ra_addr();ih->daddr() = IP_BROADCAST;ih->sport() = RT_PORT;ih->dport() = RT_PORT;ih->ttl() = IP_DEF_TTL;Scheduler::instance().schedule(target_, p, JITTER);}voidProtoname::reset_protoname_pkt_timer() {pkt_timer_.resched((double)5.0);}voidProtoname::forward_data(Packet* p) {struct hdr_cmn* ch = HDR_CMN(p);struct hdr_ip* ih = HDR_IP(p);if (ch->direction() == hdr_cmn::UP &&((u_int32_t)ih->daddr() == IP_BROADCAST || ih->daddr() == ra_addr())) { dmux_->recv(p, 0);return;}else {ch->direction() = hdr_cmn::DOWN;ch->addr_type() = NS_AF_INET;if ((u_int32_t)ih->daddr() == IP_BROADCAST)ch->next_hop() = IP_BROADCAST;else {nsaddr_t next_hop = rtable_.lookup(ih->daddr());if (next_hop == IP_BROADCAST) {debug("%f: Agent %d can not forward a packet destined to %d\n", CURRENT_TIME,ra_addr(),ih->daddr());drop(p, DROP_RTR_NO_ROUTE);return;}elsech->next_hop() = next_hop;}Scheduler::instance().schedule(target_, p, 0.0);}}(3)protoname_pkt.h#ifndef __protoname_pkt_h__#define __protoname_pkt_h__#include <packet.h>#define HDR_PROTONAME_PKT(p) hdr_protoname_pkt::access(p) struct hdr_protoname_pkt {nsaddr_t pkt_src_; // Node which originated this packetu_int16_t pkt_len_; // Packet length (in bytes)u_int8_t pkt_seq_num_; // Packet sequence numberinline nsaddr_t& pkt_src() { return pkt_src_; }inline u_int16_t& pkt_len() { return pkt_len_; }inline u_int8_t& pkt_seq_num() { return pkt_seq_num_; }static int offset_;inline static int& offset() { return offset_; }inline static hdr_protoname_pkt* access(const Packet* p) { return (hdr_protoname_pkt*)p->access(offset_);}};#endif(4)protoname_rtable.h#ifndef __protoname_rtable_h__#define __protoname_rtable_h__#include <trace.h>#include <map>typedef std::map<nsaddr_t, nsaddr_t> rtable_t;class protoname_rtable {rtable_t rt_;protoname_rtable();void print(Trace*);void clear();void rm_entry(nsaddr_t);void add_entry(nsaddr_t, nsaddr_t);nsaddr_t lookup(nsaddr_t);u_int32_t size();};#endif(5)protoname_#include "protoname_rtable.h"#include "ip.h"protoname_rtable::protoname_rtable() { }voidprotoname_rtable::print(Trace* out) {sprintf(out->pt_->buffer(), "P\tdest\tnext");out->pt_->dump();for (rtable_t::iterator it = rt_.begin(); it != rt_.end(); it++) {sprintf(out->pt_->buffer(), "P\t%d\t%d", (*it).first, (*it).second);out->pt_->dump();}}voidprotoname_rtable::clear() {rt_.clear();}voidprotoname_rtable::rm_entry(nsaddr_t dest) {rt_.erase(dest);}voidprotoname_rtable::add_entry(nsaddr_t dest, nsaddr_t next) {rt_[dest] = next;}protoname_rtable::lookup(nsaddr_t dest) {rtable_t::iterator it = rt_.find(dest);if (it == rt_.end())return IP_BROADCAST;elsereturn (*it).second;}u_int32_tprotoname_rtable::size() {return rt_.size();}step 3:我们需要对ns2中的一些文件进行修改,来使这个协议在tcl中被调用,需要修改的文件有以下几个,你可以在ns目录下找到它们:Common/packet.hTrace/cmu-trace.hTrace/Tcl/lib/ns-packet.tclTcl/lib/ns-default.tclTcl/lib/ns-lib.tclQueue/Makefilestep4:需要修改的具体内容(在需要修改的地方添加红色的字)mon/packet.h (两个需要修改的地方)1: enum packet_t {2: PT_TCP,3: PT_UDP,4: PT_CBR,5: /* ... much more packet types ... */6: PT_PROTONAME,7: PT_NTYPE // This MUST be the LAST one8: };=======================================1: p_info() {2: name_[PT_TCP]= "tcp";3: name_[PT_UDP]= "udp";4: name_[PT_CBR]= "cbr";5: /* ... much more names ... */6: name_[PT_PROTONAME]= "protoname";7: }2.T race/cmu-trace.h (一个)1: class CMUTrace : public Trace {2: /* ... definitions ... */3: private:4: /* ... */5: void format_aodv(Packet *p, int offset);6: void format_protoname(Packet *p, int offset);7: };3.T race/ (三个,先在最上面加头文件,在找一个合适的地方加函数)1: #include <protoname/protoname_pkt.h>2:3: /* ... */4:5: void6: CMUTrace::format_protoname(Packet *p, int offset)7: {8: struct hdr_protoname_pkt* ph = HDR_PROTONAME_PKT(p);9:10: if (pt_->tagged()) {11: sprintf(pt_->buffer() + offset,12: "-protoname:o %d -protoname:s %d -protoname:l %d ",13: ph->pkt_src(),14: ph->pkt_seq_num(),15: ph->pkt_len());16: }17: else if (newtrace_) {18: sprintf(pt_->buffer() + offset,19: "-P protoname -Po %d -Ps %d -Pl %d ",20: ph->pkt_src(),21: ph->pkt_seq_num(),22: ph->pkt_len());23: }24: else {25: sprintf(pt_->buffer() + offset,26: "[protoname %d %d %d] ",27: ph->pkt_src(),28: ph->pkt_seq_num(),29: ph->pkt_len());30: }31: }========================================= 1: void2: CMUTrace::format(Packet* p, const char *why)3: {4: /* ... */5: case PT_PING:6: break;7:8: case PT_PROTONAME:9: format_protoname(p, offset);10: break;11:12: default:13: /* ... */14: }4.T cl/lib/ns-packet.tcl(一个)1: foreach prot {2: Protoname3: AODV4: ARP5: # ...6: NV7: } {8: add-packet-header $prot9: }5.T cl/lib/ns-default.tcl(一个)1: # ...2: # Defaults defined for Protoname3: Agent/Protoname set accessible_var_ true6.T cl/lib/ns-lib.tcl(两个)1: Simulator instproc create-wireless-node args {2: # ...3: switch -exact $routingAgent_ {4: Protoname {5: set ragent [$self create-protoname-agent $node]6: }7: # ...8: }9: # ...10: }======================================= 1: Simulator instproc create-protoname-agent { node } { 2: # Create Protoname routing agent3: set ragent [new Agent/Protoname [$node node-addr]] 4: $self at 0.0 "$ragent start"5: $node set ragent_ $ragent6: return $ragent7: }7.Queue/(一个)1: void2: PriQueue::recv(Packet *p, Handler *h)3: {4: struct hdr_cmn *ch = HDR_CMN(p);5:6: if (Prefer_Routing_Protocols) {7:8: switch(ch->ptype()) {9: case PT_DSR:10: case PT_MESSAGE:11: case PT_TORA:12: case PT_AODV:13: case PT_PROTONAME:14: recvHighPriority(p, h);15: break;16:17: default:18: Queue::recv(p, h);19: }20: }21: else {22: Queue::recv(p, h);23: }24: }8.Makefile(一个)1: OBJ_CC = \2: tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o \ 3: # ...4: protoname/protoname.o protoname/protoname_rtable.o \5: # ...6: $(OBJ_STL)step 5:编译在ns目录下输入下名命令进行编译:$ make clean$ touch common/$ make到这里,我们添加新协议的过程就结束了。
這個章節最主要的目的就是希望使用者可以學會如何新增或修改ns2的核心模組,更明確的說就是去新增和修改[*.cc, *.h]檔案,以筆者和筆者朋友學習ns2的經驗來說,這需要花很多時間和很大的勇氣,時間是花來找資料,勇氣是用來承受當程式寫不好時,ns2可能隨時會當掉。
不過別怕,只要跟著筆者所介紹的方法,一定可以成功,若是不成功,就寫信給筆者吧。
若是一開始就要叫ns2的新手去增加的模組,新手一定會哇哇叫,所以筆者不會這樣做,筆者先教大家拷貝ns2已經有的模組檔,但改成別的名字,這樣就可以輕鬆且很明確知道該如何增加模組。
(1)(1)打開cygwin的命令視窗,把路徑切換到queue的目錄下。
cd ns-allinone-2.27/ns-2.27/queue(2)(2)拷貝drop-tail.[cc, h]到myfifo.[cc.h]。
cp cp drop-tail.h myfifo.h(3)(3)使用文字編輯軟體去修改myfifo.h和。
(因為我們的環境是在windows下,所以建議可以使用ultra-edit來修改。
a. a.先修改myfifo.h,使用取代的功能把所有DropTail改成myfifo,另外,把drop_tail改成myfifo。
#ifndef ns_myfifo_h#define ns_myfifo_h#include <string.h>#include "queue.h"#include "config.h"/** A bounded, drop-tail queue*/class myfifo : public Queue {public:myfifo() {q_ = new PacketQueue;pq_ = q_;bind_bool("drop_front_", &drop_front_);bind_bool("summarystats_", &summarystats);bind_bool("queue_in_bytes_", &qib_); // boolean: q in bytes?bind("mean_pktsize_", &mean_pktsize_);// _RENAMED("drop-front_", "drop_front_");}~myfifo() {delete q_;}protected:void reset();int command(int argc, const char*const* argv);void enque(Packet*);Packet* deque();void shrink_queue(); // To shrink queue and drop excessive packets.PacketQueue *q_; /* underlying FIFO queue */int drop_front_; /* drop-from-front (rather than from tail) */int summarystats;void print_summarystats();int qib_; /* bool: queue measured in bytes? */int mean_pktsize_; /* configured mean packet size in bytes */};#endifb. b.再修改,使用取代的功能把所有DropTail改成myfifo,另外,把drop_tail改成myfifo和drop-tail改成myfifo。
#include "myfifo.h"static class myfifoClass : public TclClass {public:myfifoClass() : TclClass("Queue/myfifo") {}TclObject* create(int, const char*const*) {return (new myfifo);}} class_myfifo;void myfifo::reset(){Queue::reset();}int myfifo::command(int argc, const char*const* argv) {if (argc==2) {if (strcmp(argv[1], "printstats") == 0) {print_summarystats();return (TCL_OK);}if (strcmp(argv[1], "shrink-queue") == 0) {shrink_queue();return (TCL_OK);}}if (argc == 3) {if (!strcmp(argv[1], "packetqueue-attach")) {delete q_;if (!(q_ = (PacketQueue*) TclObject::lookup(argv[2])))return (TCL_ERROR);else {pq_ = q_;return (TCL_OK);}}}return Queue::command(argc, argv);}/** drop-tail*/void myfifo::enque(Packet* p){if (summarystats) {Queue::updateStats(qib_?q_->byteLength():q_->length());}int qlimBytes = qlim_ * mean_pktsize_;if ((!qib_ && (q_->length() + 1) >= qlim_) ||(qib_ && (q_->byteLength() + hdr_cmn::access(p)->size()) >= qlimBytes)){ // if the queue would overflow if we added this packet...if (drop_front_) { /* remove from head of queue */q_->enque(p);Packet *pp = q_->deque();drop(pp);} else {drop(p);}} else {q_->enque(p);}}//AG if queue size changes, we drop excessive packets...void myfifo::shrink_queue(){int qlimBytes = qlim_ * mean_pktsize_;if (debug_)printf("shrink-queue: time %5.2f qlen %d, qlim %d\n",Scheduler::instance().clock(),q_->length(), qlim_);while ((!qib_ && q_->length() > qlim_) ||(qib_ && q_->byteLength() > qlimBytes)) {if (drop_front_) { /* remove from head of queue */Packet *pp = q_->deque();drop(pp);} else {Packet *pp = q_->tail();q_->remove(pp);drop(pp);}}}Packet* myfifo::deque(){if (summarystats && &Scheduler::instance() != NULL) {Queue::updateStats(qib_?q_->byteLength():q_->length());}return q_->deque();}void myfifo::print_summarystats(){//double now = Scheduler::instance().clock();printf("True average queue: %5.3f", true_ave_);if (qib_)printf(" (in bytes)");printf(" time: %5.3f\n", total_time_);}(4)(4)修改ns-default.tcl檔,設定初始內定值。
a. a.cd ns-allinone-2.27/ns-2.27/tcl/lib/b. b.使用文字編輯軟體打開ns-default.tclc. c.使用搜尋的功能找到Queue/DropTaild. d.把每個初始設定值都再設一份給Queue/myfifo……………………………………………..Queue/DropTail set drop_front_ falseQueue/DropTail set summarystats_ falseQueue/DropTail set queue_in_bytes_ falseQueue/DropTail set mean_pktsize_ 500Queue/myfifo set drop_front_ falseQueue/myfifo set summarystats_ falseQueue/myfifo set queue_in_bytes_ falseQueue/myfifo set mean_pktsize_ 500……………………………………………..(5)(5)修改Makefile,把myfifo.o加入OBJ_CC內,並重新編譯。
a. a.使用文字編輯軟體打開ns-allinone-2.27/ns-2.27目錄下的Makefileb. b.使用搜尋找到drop-tail.o。
c. c.在drop-tail.o後面加上queue/myfifo。
……………………………………………..tools/flowmon.o tools/loss-monitor.o \queue/queue.o queue/drop-tail.o queue/myfifo.o \adc/simple-intserv-sched.o queue/red.o \……………………………………………d. d.重新編譯。