本文介绍如何在最新版的NS2.35中嵌入一个自己写的简单新协议,读者可先不必较真协议的具体实现代码,先熟悉嵌入流程因为此代码还是有一定bug的,但实现一个协议的总体框架是对的。后续文章将对如何写一个新协议进行解析,如TCL如何传值到C++等。
我们在 NS_HOME 根目录下创建一个文件夹 kgn,目录下有两个文件: simple_trans.h和simple_trans.cc,这两个文件就是我们新协议的主体实现文件。
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 //同步指令(类似于 TCP 协议中三次握手的第一步,事实上我们的这个协议最终就是要实现一个简化版的三步握手) #define PROTOCOL_INIT_SYN 1 //只有 type 这个是我定义的,其他的内容是 ns2 系统需要的 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_); } }; //产生数据包、发送数据包、接收数据包的地方,包括的 target 变量就是数据包发送给的下一个目标。 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); }; //一个定时器(闹钟)在到时时候会调用一个 expire (超时)函数 class SYNTimer : public TimerHandler { public: SYNTimer(simple_trans_agent* t) : TimerHandler(), t_(t) { } inline virtual void expire(Event *); protected: simple_trans_agent* t_; }; #endifsimple_trans.cc代码内容
#include "simple_trans.h" //显示系统时间 #define NOW Scheduler::instance().clock() //得到当前节点的地址 #define MYNODE Address::instance().get_nodeaddr(addr()) 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_); } } class_simple_transhdr; static class simple_transClass : public TclClass { public: simple_transClass() : TclClass("Agent/simple_trans") {} TclObject* create(int, const char*const*) { return (new simple_trans_agent()); } } class_simple_trans; simple_trans_agent::simple_trans_agent() : Agent(PT_SIMPLE_TRANS_PACKET), simple_target(-1), simple_port(PROTOCOL_DEFAULT_PORT) { bind("simple_target_", &simple_target); bind("simple_port_", &simple_port); } //到时了就发送我们的 SYN 信息给我们的目标节点 void SYNTimer::expire(Event *){ t_->send_simple_msg(PROTOCOL_INIT_SYN, t_->get_target()); this->resched(1.00); } void simple_trans_agent::send_simple_msg(int type, int target) { //数据包的生成 Packet* pkt = allocpkt(); //数据包的访问 hdr_ip *iph = hdr_ip::access(pkt); hdr_simple_trans *shdr = hdr_simple_trans::access(pkt); if( type == PROTOCOL_INIT_SYN) { if( simple_target != -1 ) { iph->daddr() = simple_target; } else { printf(" no target specificed \n "); return ; } iph->dport() = simple_port; iph->saddr() = MYNODE; shdr->type = PROTOCOL_INIT_SYN; send( pkt, 0 ); } } int simple_trans_agent::command(int argc, const char*const* argv) { if( argc == 2 ) { if( !strcmp( argv[1], "begin" ) ) { //sendsend_simple_msg( PROTOCOL_INIT_SYN, simple_target ); SYNTimer *syn_timer = new SYNTimer(this); syn_timer->resched(1.00); return (TCL_OK); } } if( argc == 3 ) { if( !strcmp( argv[1], "set-target" ) ) { simple_target = atoi( argv[2] ); printf("=>set-target = %d \n ", simple_target); return (TCL_OK); } } return (Agent::command(argc, argv)); } void simple_trans_agent::recv(Packet *p, Handler *) { hdr_ip *iph = hdr_ip::access(p); hdr_simple_trans *shdr = hdr_simple_trans::access(p); if( shdr->type == PROTOCOL_INIT_SYN ) { printf("=>At %lf node %d receive PROTOCOL_INIT_SYN signaling from node %d \n", NOW, MYNODE, iph->saddr()); } else { printf(" wrong type siganling \n"); } }
在 NS_HOME/common/packet.h 加入static const packet_t PT_SIMPLE_TRANS_PACKET = 74;
在 class p_info 中加入name_[PT_SIMPLE_TRANS_PACKET] = "simple_trans_packet" (非必须的)。
packet.h关键代码内容:
//add by song static const packet_t PT_SIMPLE_TRANS_PACKET = 73; // insert new packet types here static packet_t PT_NTYPE = 74; // This MUST be the LAST one
name_[PT_NTYPE]= "undefined"; // add by song name_[PT_SIMPLE_TRANS_PACKET] = "SIMPLE_trans_packet";
最后一步,就是编译我们整个协议将其键入到 ns 中了,编译前我们要修改 makefile 文件,由于我们是在 NS_HOME/kgn 目录中所以, makefile 需要修改的有两个地方:
在 INCLUDES = 中加入 -I./kgn ,加入这个的好处就是我们在其他目录使用 simple_trans.h 的时候不用将 kgn 次级目录包含进去;
在 OBJ_CC = 中加入 kgn/simple_trans.o \ 。
makefile关键代码内容:
INCLUDES = \ -I. \ -I. \ -I/home/song/ns-allinone-2.35/tclcl-1.20 -I/home/song/ns-allinone-2.35/otcl-1.14 -I/home/song/ns-allinone-2.35/include -I/home/song/ns-allinone-2.35/include -I/home/song/ns-allinone-2.35/include -I/usr/include/pcap \ -I./tcp -I./sctp -I./common -I./link -I./queue \ -I./adc -I./apps -I./mac -I./mobile -I./trace \ -I./routing -I./tools -I./classifier -I./mcast \ -I./diffusion3/lib/main -I./diffusion3/lib \ -I./diffusion3/lib/nr -I./diffusion3/ns \ -I./diffusion3/filter_core -I./asim/ -I./qs \ -I./diffserv -I./satellite \ -I./wpan\ -I./kgn
OBJ_CC = \ tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o \ common/scheduler.o common/object.o common/packet.o \ common/ip.o routing/route.o common/connector.o common/ttl.o \ trace/trace.o trace/trace-ip.o \ classifier/classifier.o classifier/classifier-addr.o \ classifier/classifier-hash.o \ classifier/classifier-virtual.o \ classifier/classifier-mcast.o \ classifier/classifier-bst.o \ classifier/classifier-mpath.o mcast/replicator.o \ classifier/classifier-mac.o \ classifier/classifier-qs.o \ classifier/classifier-port.o src_rtg/classifier-sr.o \ src_rtg/sragent.o src_rtg/hdr_src.o adc/ump.o \ qs/qsagent.o qs/hdr_qs.o \ apps/app.o apps/telnet.o tcp/tcplib-telnet.o \ tools/trafgen.o trace/traffictrace.o tools/pareto.o \ tools/expoo.o tools/cbr_traffic.o \ adc/tbf.o adc/resv.o adc/sa.o tcp/saack.o \ tools/measuremod.o adc/estimator.o adc/adc.o adc/ms-adc.o \ adc/timewindow-est.o adc/acto-adc.o \ adc/pointsample-est.o adc/salink.o adc/actp-adc.o \ adc/hb-adc.o adc/expavg-est.o\ adc/param-adc.o adc/null-estimator.o \ adc/adaptive-receiver.o apps/vatrcvr.o adc/consrcvr.o \ common/agent.o common/message.o apps/udp.o \ common/session-rtp.o apps/rtp.o tcp/rtcp.o \ common/ivs.o \ common/messpass.o common/tp.o common/tpm.o apps/worm.o \ tcp/tcp.o tcp/tcp-sink.o tcp/tcp-reno.o \ tcp/tcp-newreno.o \ tcp/tcp-vegas.o tcp/tcp-rbp.o tcp/tcp-full.o tcp/rq.o \ baytcp/tcp-full-bay.o baytcp/ftpc.o baytcp/ftps.o \ tcp/scoreboard.o tcp/scoreboard-rq.o tcp/tcp-sack1.o tcp/tcp-fack.o \ tcp/scoreboard1.o tcp/tcp-linux.o tcp/linux/ns-linux-util.o \ tcp/tcp-asym.o tcp/tcp-asym-sink.o tcp/tcp-fs.o \ tcp/tcp-asym-fs.o \ tcp/tcp-int.o tcp/chost.o tcp/tcp-session.o \ tcp/nilist.o \ sctp/sctp.o apps/sctp_app1.o\ sctp/sctp-timestamp.o sctp/sctp-hbAfterRto.o \ sctp/sctp-multipleFastRtx.o sctp/sctp-mfrHbAfterRto.o \ sctp/sctp-mfrTimestamp.o \ sctp/sctp-cmt.o \ sctp/sctpDebug.o \ dccp/dccp_sb.o \ dccp/dccp_opt.o \ dccp/dccp_ackv.o \ dccp/dccp_packets.o \ dccp/dccp.o \ dccp/dccp_tcplike.o \ dccp/dccp_tfrc.o \ tools/integrator.o tools/queue-monitor.o \ tools/flowmon.o tools/loss-monitor.o \ queue/queue.o queue/drop-tail.o \ adc/simple-intserv-sched.o queue/red.o \ queue/semantic-packetqueue.o queue/semantic-red.o \ tcp/ack-recons.o \ queue/sfq.o queue/fq.o queue/drr.o queue/srr.o queue/cbq.o \ queue/jobs.o queue/marker.o queue/demarker.o \ link/hackloss.o queue/errmodel.o queue/fec.o\ link/delay.o tcp/snoop.o \ gaf/gaf.o \ link/dynalink.o routing/rtProtoDV.o common/net-interface.o \ mcast/ctrMcast.o mcast/mcast_ctrl.o mcast/srm.o \ common/sessionhelper.o queue/delaymodel.o \ mcast/srm-ssm.o mcast/srm-topo.o \ routing/alloc-address.o routing/address.o \ $(LIB_DIR)int.Vec.o $(LIB_DIR)int.RVec.o \ $(LIB_DIR)dmalloc_support.o \ webcache/http.o webcache/tcp-simple.o webcache/pagepool.o \ webcache/inval-agent.o webcache/tcpapp.o webcache/http-aux.o \ webcache/mcache.o webcache/webtraf.o \ webcache/webserver.o \ webcache/logweb.o \ empweb/empweb.o \ empweb/empftp.o \ realaudio/realaudio.o \ mac/lanRouter.o classifier/filter.o \ common/pkt-counter.o \ common/Decapsulator.o common/Encapsulator.o \ common/encap.o \ mac/channel.o mac/mac.o mac/ll.o mac/mac-802_11.o \ mac/mac-802_11Ext.o \ mac/mac-802_3.o mac/mac-tdma.o mac/smac.o \ mobile/mip.o mobile/mip-reg.o mobile/gridkeeper.o \ mobile/propagation.o mobile/tworayground.o \ mobile/nakagami.o \ mobile/antenna.o mobile/omni-antenna.o \ mobile/shadowing.o mobile/shadowing-vis.o mobile/dumb-agent.o \ common/bi-connector.o common/node.o \ common/mobilenode.o \ mac/arp.o mobile/god.o mobile/dem.o \ mobile/topography.o mobile/modulation.o \ queue/priqueue.o queue/dsr-priqueue.o \ mac/phy.o mac/wired-phy.o mac/wireless-phy.o \ mac/wireless-phyExt.o \ mac/mac-timers.o trace/cmu-trace.o mac/varp.o \ mac/mac-simple.o \ satellite/sat-hdlc.o \ dsdv/dsdv.o dsdv/rtable.o queue/rtqueue.o \ routing/rttable.o \ imep/imep.o imep/dest_queue.o imep/imep_api.o \ imep/imep_rt.o imep/rxmit_queue.o imep/imep_timers.o \ imep/imep_util.o imep/imep_io.o \ tora/tora.o tora/tora_api.o tora/tora_dest.o \ tora/tora_io.o tora/tora_logs.o tora/tora_neighbor.o \ dsr/dsragent.o dsr/hdr_sr.o dsr/mobicache.o dsr/path.o \ dsr/requesttable.o dsr/routecache.o dsr/add_sr.o \ dsr/dsr_proto.o dsr/flowstruct.o dsr/linkcache.o \ dsr/simplecache.o dsr/sr_forwarder.o \ aodv/aodv_logs.o aodv/aodv.o \ aodv/aodv_rtable.o aodv/aodv_rqueue.o \ aomdv/aomdv_logs.o aomdv/aomdv.o \ aomdv/aomdv_rtable.o aomdv/aomdv_rqueue.o \ puma/puma.o \ mdart/mdart_adp.o mdart/mdart_dht.o mdart/mdart_ndp.o \ mdart/mdart_neighbor.o mdart/mdart_queue.o mdart/mdart_table.o \ mdart/mdart.o \ common/ns-process.o \ satellite/satgeometry.o satellite/sathandoff.o \ satellite/satlink.o satellite/satnode.o \ satellite/satposition.o satellite/satroute.o \ satellite/sattrace.o \ rap/raplist.o rap/rap.o rap/media-app.o rap/utilities.o \ common/fsm.o tcp/tcp-abs.o \ diffusion/diffusion.o diffusion/diff_rate.o diffusion/diff_prob.o \ diffusion/diff_sink.o diffusion/flooding.o diffusion/omni_mcast.o \ diffusion/hash_table.o diffusion/routing_table.o diffusion/iflist.o \ tcp/tfrc.o tcp/tfrc-sink.o mobile/energy-model.o apps/ping.o tcp/tcp-rfc793edu.o \ queue/rio.o queue/semantic-rio.o tcp/tcp-sack-rh.o tcp/scoreboard-rh.o \ plm/loss-monitor-plm.o plm/cbr-traffic-PP.o \ linkstate/hdr-ls.o \ mpls/classifier-addr-mpls.o mpls/ldp.o mpls/mpls-module.o \ routing/rtmodule.o classifier/classifier-hier.o \ routing/addr-params.o \ nix/hdr_nv.o nix/classifier-nix.o \ nix/nixnode.o \ routealgo/rnode.o \ routealgo/bfs.o \ routealgo/rbitmap.o \ routealgo/rlookup.o \ routealgo/routealgo.o \ nix/nixvec.o \ nix/nixroute.o \ diffserv/dsred.o diffserv/dsredq.o \ diffserv/dsEdge.o diffserv/dsCore.o \ diffserv/dsPolicy.o diffserv/ew.o diffserv/dewp.o \ queue/red-pd.o queue/pi.o queue/vq.o queue/rem.o \ queue/gk.o \ pushback/rate-limit.o pushback/rate-limit-strategy.o \ pushback/ident-tree.o pushback/agg-spec.o \ pushback/logging-data-struct.o \ pushback/rate-estimator.o \ pushback/pushback-queue.o pushback/pushback.o \ common/parentnode.o trace/basetrace.o \ common/simulator.o asim/asim.o \ common/scheduler-map.o common/splay-scheduler.o \ linkstate/ls.o linkstate/rtProtoLS.o \ pgm/classifier-pgm.o pgm/pgm-agent.o pgm/pgm-sender.o \ pgm/pgm-receiver.o mcast/rcvbuf.o \ mcast/classifier-lms.o mcast/lms-agent.o mcast/lms-receiver.o \ mcast/lms-sender.o \ queue/delayer.o \ xcp/xcpq.o xcp/xcp.o xcp/xcp-end-sys.o \ wpan/p802_15_4csmaca.o wpan/p802_15_4fail.o \ wpan/p802_15_4hlist.o wpan/p802_15_4mac.o \ wpan/p802_15_4nam.o wpan/p802_15_4phy.o \ wpan/p802_15_4sscs.o wpan/p802_15_4timer.o \ wpan/p802_15_4trace.o wpan/p802_15_4transac.o \ apps/pbc.o \ kgn/simple_trans.o \ $(OBJ_STL)
# This script is created by NSG2 beta1 # <http://wushoupong.googlepages.com/nsg> #=================================== # Simulation parameters setup #=================================== Antenna/OmniAntenna set Gt_ 1 ;#Transmit antenna gain Antenna/OmniAntenna set Gr_ 1 ;#Receive antenna gain set val(chan) Channel/WirelessChannel ;# channel type set val(prop) Propagation/TwoRayGround ;# radio-propagation model set val(netif) Phy/WirelessPhy ;# network interface type set val(mac) Mac/802_11 ;# MAC type set val(ifq) Queue/DropTail/PriQueue ;# interface queue type set val(ll) LL ;# link layer type set val(ant) Antenna/OmniAntenna ;# antenna model set val(ifqlen) 50 ;# max packet in ifq set val(nn) 2 ;# number of mobilenodes set val(rp) DSDV ;# routing protocol set val(x) 499 ;# X dimension of topography set val(y) 401 ;# Y dimension of topography set val(stop) 10.0 ;# time of simulation end #=================================== # Initialization #=================================== #Create a ns simulator set ns [new Simulator] #Setup topography object set topo [new Topography] $topo load_flatgrid $val(x) $val(y) create-god $val(nn) #Open the NS trace file set tracefile [open out.tr w] $ns trace-all $tracefile #Open the NAM trace file set namfile [open out.nam w] $ns namtrace-all $namfile $ns namtrace-all-wireless $namfile $val(x) $val(y) set chan [new $val(chan)];#Create wireless channel #=================================== # Mobile node parameter setup #=================================== $ns node-config -adhocRouting $val(rp) \ -llType $val(ll) \ -macType $val(mac) \ -ifqType $val(ifq) \ -ifqLen $val(ifqlen) \ -antType $val(ant) \ -propType $val(prop) \ -phyType $val(netif) \ -channel $chan \ -topoInstance $topo \ -agentTrace ON \ -routerTrace ON \ -macTrace ON \ -movementTrace ON #=================================== # Nodes Definition #=================================== #Create 2 nodes set n0 [$ns node] $n0 set X_ 300 $n0 set Y_ 300 $n0 set Z_ 0.0 $ns initial_node_pos $n0 20 set n1 [$ns node] $n1 set X_ 545 $n1 set Y_ 300 $n1 set Z_ 0.0 $ns initial_node_pos $n1 20 #=================================== # Agents Definition #=================================== set sT1 [new Agent/simple_trans] #$sT1 set-target [AddrParams addr2id [$n1 node-addr]] $sT1 set simple_target_ [AddrParams addr2id [$n1 node-addr]] $n0 attach $sT1 1023 set sT2 [new Agent/simple_trans] $n1 attach $sT2 1023 $sT2 set interval_ 0.1 #=================================== # Applications Definition #=================================== #=================================== # Termination #=================================== #Define a 'finish' procedure proc finish {} { global ns tracefile namfile $ns flush-trace close $tracefile close $namfile #exec nam out.nam & exit 0 } for {set i 0} {$i < $val(nn) } { incr i } { $ns at $val(stop) "\$n$i reset" } $ns at 1.0 "$sT1 begin" $ns at $val(stop) "$ns nam-end-wireless $val(stop)" $ns at $val(stop) "finish" $ns at $val(stop) "puts \"done\" ; $ns halt" $ns run
参考文献:《如何在ns2中实现一个简单的网络协议》,原文基于2.31版本,本文在此基础上移植到2.35版本,进行代码修改使之适应新版并对关键代码进行注释。