NS2的NODE类——node

article/2025/10/10 0:33:57

本文转自:http://hi.baidu.com/wirelesscat/blog/item/67c6db4633f71e016b63e59b.html

同时推荐一个很好的博客,这里有连载的 ns2 仿真问题,感谢大牛~~~

博客地址:http://hi.baidu.com/wirelesscat/blog/category/ns-2


Node是网络拓扑的重要组成部分,时NS2复合网络组件的一个大类。复合组件(如node和link)不是TclObject类的派生类,而是NS2中独立的类,一个ns2节点本质是一个分类器的集合。

节点结构图:
每个节点至少包含一下几个部分:一个地址或者id_,初始值是0,当节点建立时模拟的名字空间将自动加1;一个邻居链表neighbor_;一个代理链表agent_;一个节点类型识别器nodetype_;一个路由模块。
Tcl对象:1)地址分类器(address classifier),用来判断分组的目标地址,把传入的包分派到正确的链路。
~ns/classifier/classifier-addr.{h/cc};
            2)端口分类器(port classifier),用来判断分组的目标Agent,把传入的包分派到争取的代理。~ns/classifier/classifier-port.{ h/cc}。

节点建立:
set ns [new Simulator]                      set ns [new Simulator -multicast on]
$ns node
设置节点:(控制函数、地址和端口号管理、代理管理、添加邻居)
控制函数:$node entry:返回节点入口地址;$node reset:重新设置节点上所有代理。
地址和端口号管理:$node id:返回节点的节点号;$node agent(port):返回一个端口号为port的代理的句柄;
             alloc-port:返回下一个可获得的端口号;
             add-route/routes:单播时增加路由路径从而产生classifier_。$node add-route <destination id> <TclObject>
                                       $node add-routes <destination id> <TclObjects>添加多重路由路径到同一个目的地。
             delete-routes():包括参数id,一个TclObject的列表和一个模拟器的空代理的指针。
代理管理:attach():把制定的代理加入到一个agents_链表中,给该代理分配一个端口号并设置它的源地址。设置代理的指针为它的入口。例如节点的entry()添加一个节点上的多路服用的端口(dmux_)的指针到代理相应的dmux_分类器。相反的detach()从代理
agents_中移除代理,代理目标指针指向空代理的入口。
添加邻居:过程add-neighbor()用于增加一个邻居到这个链表中,neighbors()用于返回邻居链表。

配置节点:
  使用函数simulator::node-config{}配置即将创建的节点属性,这种节点配置方法主要针对移动节点和卫星。
  e.g: 

#设定模拟需要的一些属性,比如mobilenode的Channel、MAC、LL层的类型,天线类型,节点数目,场景的长宽尺寸等。
  set val(chan) Channel/WirelessChannel ;#信道类型
  set val(prop) Propagation/TwoRayGround ;#无线-传播模型
  set val(netif) Phy/WirelessPhy ;#网络接口类型
  set val(mac) Mac/802_11 ;#MAC类型
  set val(ifq) Queue/DropTail/PriQueue ;#接口队列类型
  set val(ll) LL ;#链路层类型
  set val(ant) Antenna/OmniAntenna ;#天线模型
  set val(ifqlen) 50 ;#ifq中的最大分组
  set val(nn) 2 ;#移动节点数
  set val(rp) AODV ;#路由协议
  set val(x) 500 ;#拓扑结构的X轴范围
  set val(y) 500 ;#拓扑结构的Y轴范围
  $set ns [new Simulator]
#建立节点(mobilenode)之前,先配置节点的一些参数。agentTrace表示应用层的trace,在trace文件中用#AGT表示;routerTrace表示路由的trace,在toace文件中用RTR表示;macTrace表示MAC层的trace,
#在trace文件中用MAC表示;movementTrace表示记录节点移动命令的trace,在trace文件中用M表示。
  $ns node-config -addressType def\ ;#设定节点地址类型:def(flat) & hierarchical
  -adhocRouting $val(rp) \ ;#设定移动节点所使用的路由协议
  -llType $val(ll) \ ;#设定移动节点的逻辑链路层
  -macType $val(mac) \ ;#设定移动节点的MAC层
  -ifqType $val(ifq) \ ;#设定移动节点的队列类型
  -ifqLen $val(ifqlen) \ ;#设定移动节点的队列长度
  -antType $val(ant) \ ;#设定移动节点的天线类型
  -propType $val(prop) \ ;#设定移动节点的无线信号传输模型
  -phyType $val(netif) \ ;#设定移动节点物理层类型
  -channelType $val(chan) \ ;#设定移动节点的无线信道类型
  -topoInstance $topo \ ;#设定移动节点的拓扑对象
  -agentTrace ON \ ;#是否打开应用层的trace
  -routerTrace ON \ ;#是否打开路由的trace
  -macTrace OFF \ ;#是否打开MAC层的trace
  -movementTrace OFF ;#是否打开节点位置和移动信息的trace

#建立两个节点(mobilenode),关闭节点的随机运动功能,即节点的运动完全由我们指定。
  for {set i 0} {$i > shift_) & mask_); }
   virtual void recv(Packet* p, Handler* h);
  //recv()函数的实现参考源文件~ns/classifier/classifier.cc
   virtual NsObject* find(Packet*);
  // find()函数的实现参考源文件~ns/classifier/classifier.cc
   virtual int classify(Packet *);
   virtual void clear(int slot); //从表中删除对象
   virtual void install(int slot, NsObject*); //从表中增加对象
  protected:
   virtual int command(int argc, const char*const* argv);
   void alloc(int); // alloc()函数动态的分配足够的空间来放置slot
   NsObject** slot_; /* table that maps slot number to a NsObject */
   int nslot_;
   int maxslot_;
   int offset_; // offset for Packet::access()
   int shift_;
   int mask_;
   NsObject *default_target_;
   int nsize_; //what size of nslot_ should be
  };
  ——————————————————————————————————
  e.g:~ns/classifier/classifier.cc
  void Classifier::recv(Packet* p, Handler*h)
  {
   NsObject* node = find(p);
   if (node == NULL) {
   Packet::free(p);
   return;
   }
   node->recv(p,h);
  }
  NsObject* Classifier::find(Packet* p)
  {
   NsObject* node = NULL;
   int cl = classify(p);
   if (cl = nslot_ || (node = slot_[cl]) == 0) {
   if (default_target_)
   return default_target_;
   Tcl::instance().evalf("%s no-slot %ld", name(), cl);
   if (cl == TWICE) {
   cl = classify(p);
   if (cl = nslot_ || (node = slot_[cl]) == 0)
   return (NULL);
   }
   }
   return (node);
  }
  当classifier收到一个分组时(即recv()函数被调用时),recv()函数首先调用find()函数来处理该分组,find()函数会调用classify()函数,不同类型的classifier对classify()函数定义不同,但各种classify函数都会对分组作检查然后返回一个slot索引值。如果索引值有效,并指向一个有效的TclObject,recv()函数就会把分组传递给该TclObject,即调用该TclObject的recv()函数;如果索引无效,就会清除该分组并返回。
  ——————————————————————————————————
  几种主要的Classifier类:
  1.address classifier:按分组目的地址进行匹配,用来支持单播分组转发,通过对分组的目的地址做位运算来产生一个slot number。该类对应的classify()函数定义参考~ns/classifier/classifier-addr.cc。
  ——————————————————————————————————
  int AddressClassifier::classify(Packet *p)
  {
   hdr_ip* iph = hdr_ip::access(p);
   return mshift(iph->daddr());
  };
  iph->daddr()函数返回分组IP头中的目的地址,mshift(int val)函数的定义在前面Classifier类的定义中可以找到,其中mask_和shift_的值可以通过Otcl来设置,缺省值分别为0xffffffff和0,即mshift(int val)直接返回val的值。
  ——————————————————————————————————
  2.port classifier:按分组目的端口进行匹配,将分组传递给相应的Agent对象。该类对应的classify()函数定义参考~ns/classifier/classifier-addr.cc。
 ——————————————————————————————————
  int PortClassifier::classify(Packet *p)
  {
   hdr_ip* iph = hdr_ip::access(p);
   return iph->dport();
  };
  iph->dport()函数返回分组IP头中的目的端口。
  ——————————————————————————————————
  3.replicator:与普通classifier不同,不使用classify()函数,作用是生成一个分组的多份拷贝,并把这些拷贝转发给slot表中的所有对象。在组播分组转发时,一个分组需要被转发给多个目标对象,生成分组拷贝的工作由replicator完成。Replicator类的定义及其recv()函数的定义参考~ns/mcast/replicator.cc。
  ——————————————————————————————————
  class Replicator : public Classifier
  {
  public:
   Replicator();
   void recv(Packet*, Handler* h = 0);
   virtual int classify(Packet*) {/*NOTREACHED*/ return -1;};
  protected:
   virtual int command(int argc, const char*const* argv);
   int ignore_;
   int direction_;
  };
  void Replicator::recv(Packet* p, Handler*)
  {
   hdr_ip* iph = hdr_ip::access(p);
   hdr_cmn* ch = hdr_cmn::access(p);
   if (maxslot_ saddr(), iph->daddr(), ch->iface());
   Packet::free(p);
   return;
   }
  ……
   for (int i = 0; i recv(p->copy());
   }
   /* we know that maxslot is non-null */
   slot_[maxslot_]->recv(p);
  }
  可以看到Replicator类的recv()函数并不调用classify()函数,它只是为slot表中的每一个对象复制一份该分组的拷贝,并把拷贝发送给该对象,表中的最后一个对象收到的是原始的分组,而原始分组和拷贝实际上是完全一样的。


  ——————————————————————————————————
  Classifier类提供了一些Tcl实例过程,用户可以在Tcl中对Classifier对象进行控制。主要实例过程:
  1. alloc-port :寻找一个空闲的slot。
  2. clear :将号码为index的slot清空。
  3. installNext:在最后一个slot后插入一个新的指向object的表项,并返回该表项的slot号码:如果object为空,会返回错误信息。
  4. slot :产旬号码为index的slot对应对象名,如果该slot为空,会返回错误信息。
  5. findslot:查询一个object所在的slot号码,如果该object为空,会返回错误信息,如果在表中没有找到该object,会返回-1。
  6. install :将号码为index的slot所指向的对象设为object。
  e.g. Classifier类部分Tcl实例过程的使用方法举例,参见

  ——————————————————————————————————
  set ns [new Simulator] ;#建立一个Simulator对象的实例并把它赋值给变量ns。
  set node [$ns node] ;#新建一个节点并赋值给node。
  set udp0 [new Agent/UDP] ;#新建一个UDP Agent并赋值给udp0。
  set udp1 [new Agent/UDP] ;#新建一个UDP Agent并赋值给udp1。
  set null [new Agent/Null] ;#新建一个UDP Agent并赋值给null。
  $ns attach-agent $node $udp0; #将UDP Agent udp0绑定到node上。
  puts "[[$node set dmux_] slot 0]" ;#查询号码为0的slot对应的对象名并将其输出。
  puts "$udp0" ;#输出udp0的值。
  puts "[[$node set dmux_] findslot $udp0]" ;#查询udp0所在的slot号码并输出。
  puts "[[$node set dmux_] findslot $null]" ;#查询null所在的slot号码,表中没有找到该对象,返回-1,并输出。
  puts "============================================="
  puts "[[$node set dmux_] installNext $udp1]";#在最后一个slot 0后插入一个新的指向对象udp1的表项,返回
  ;#该表项的slot号码1,并输出。
  puts "[[$node set dmux_] slot 1]" ;#查询号码为1的slot对应的对象名并将其输出。
  puts "$udp1" ;#输出udp1的值。
  puts "============================================="
  [$node set dmux_] install 0 $udp1 ;#将号码为0的slot所指向的对象设为udp1。
  puts "[[$node set dmux_] slot 0]" ;#查询号码为0的slot对应的对象名并将其输出。
  puts "============================================="
  puts "[[$node set dmux_] alloc-port $null]" ;#寻找一个空闲的slot并输出。
  [$node set dmux_] clear 0 ;# 将号码为0的slot清空。
  puts "[[$node set dmux_] alloc-port $null]" ;#寻找一个空闲的slot并输出。
  puts "============================================="
  puts "[[$node set dmux_] slot 0]" ;# 查询号码为0的slot对应的对象名,该object为空,故返回错误信息。
  $ns run
  运行结果:
  ——————————————————————————————————
  相关Tcl命令:

     1. set $node [$ns node]:建立一个节点实例。
  2. $node id:返回该节点id。
  3. $node neighbors:返回邻居节点的列表。
  4. $node add-neighbor <neighbor_node>:增加一个邻居节点(注:这是单向的邻居,即“neighbor node”是node的邻居,但node不是“neighbor node”的邻居)。
  5. $node node-addr:返回节点的地址(address)。地址类型为def时,节点地址与节点id相同;地址类型为hierarchical时,节点地址是一个字符串。
  6. $node reset:重置连到这个node上的所有agent。
  7. $node agent <port_num> :返回port_num端口所指向的agent对象,如果port_num端口没有指向任何对象,返回null字符串。
  8. $node attach <agent> <optional:port_num> :将agent对象连接到节点上,如果没有指定端口号,节点会自己分配一个空闲的端口,并把agent连接到该端口上;如果指定端口为port_num,节点会把agent连接到端口port_num上。
  9. $node detach <agent> <null_agent>:将agent与节点分离,并把一个null_agent连接到agent原来所在的端口上。
    10. $node incr-rtgtable-size对象变量rtsize_用于保持对每个节点路由表大小的记录,该命令用于当每次路由入口加入分类器时增加路由表的大小。
     11.$node add-route <destination_id> <target>用于增加单播路由的分类器,目标是一个Tcl对象,如果<destination_id>和节点的id相同,则该对象可能就是dmux_的入口(节点的端口复用器)。否则它通常是该目的链表的头。
      12.$ns_ node [<hier_addr>]创建和返回一个节点的实例。若<hier_addr>给出,指派节点地址为<hier_addr>类型。注意:当层次地址通过set-address-format hierarchical{}或者node-config-addressType hierarchical{}调用时,<hier_addr>必须被使用。

http://chatgpt.dhexx.cn/article/X8BnoSpv.shtml

相关文章

NS2问题解决

问题一&#xff1a; When configured, ns found the right version of tclsh in /usr/bin/tclsh8.6 but it doesnt seem to be there anymore, so ns will fall back on running the first tclsh in your path. The wrong version of tclsh may break the test suites. Reconfi…

NS2简单介绍

NS是一种针对网络技术的源代码公开的、免费的软件模拟平台&#xff0c;研究人员使用它可以很容易的进行网络技术的开发&#xff0c;而且发展到今天&#xff0c;它所包含的模块已经非常丰富&#xff0c;几乎涉及到了网络技术的所有方面。所以&#xff0c;NS成了目前学术界广泛使…

NS2网络仿真

NS2安装与配置TCP/UDP比较仿真静态/动态路由仿真 1.安装与配置 1.1更新系统 sudo apt-get update #更新源列表 sudo apt-get upgrade #更新已经安装的包 sudo apt-get dist-upgrade #更新软件&#xff0c;升级系统 1.2安装ns2需要的几个包 sudo apt-get install build-ess…

ns2安装详细过程与网络仿真

ns2安装详细过程与网络仿真 博客分类&#xff1a; Networks TclLinuxUnixGCCVC 简单的说&#xff0c;NS&#xff0d;2是一个网络模拟器&#xff0c;所以经常被用到网络课的教学中。 NS-2是OpenSource的&#xff0c;最早的版本是在linux/unix下运行的&#xff0c;后来有了wi…

NS2教程

柯老师的NS2新网址 Due to some reasons, my NS2 website is sometimes donw and unavailable for many users. Therefore, I provide another backup website. 1. NS2 http://csie.nqu.edu.tw/smallko/ns2/ns2.htm 2. old_NS2 (backup of NS2 Learning Guide) http://csie.n…

ns2安装和若干问题的解决方法

文章目录 1. 安装与配置2. 安装nam3. 配置环境变量4. 检查是否能够成功运行参考资料 在安装ns2的过程中遇到了很多问题&#xff0c;为了记录这些问题和为同样遇到这些问题的朋友提供思路&#xff0c;写下这篇博文。 安装ns2和nam主要分为如下几个步骤&#xff1a; 安装与配置…

Linux下安装ns2

最近为了项目需要用到NS2软件用于网络仿真实验&#xff0c;从Windows到Linux折腾了我将近一周的时间。在Windows装了卸、卸了装十几遍还是不成功&#xff0c;最后放弃了&#xff0c;回到了Linux系统&#xff0c;又折腾了两天终于安装测试成功&#xff01;&#xff08;安装其实蛮…

企业微信第三方扫码登录

为什么写这个文章 公司后台突然需要扫码登录&#xff0c;网上的企业微信扫码都是基于自建应用的扫码登录&#xff0c;对第三方的扫码并没有多加介绍 概述 企业微信的管理员和成员&#xff0c;可通过单点登录机制&#xff0c;登录到第三方网站。第三方可通过接口&#xff0c;…

微信第三方登录有两种登录方式, 1. 微信开放平台登录 2. 微信公众平台授权登录?

https://www.v2ex.com/amp/t/390333 微信开放平台登录与微信公众平台授权登录区别在哪? 2017-09-13 12:05:41 08:00 xoxo419 微信第三方登录有两种登录方式, 1. 微信开放平台登录 2. 微信公众平台授权登录? 问: 两者区别在哪? 壹号店 http://m.yhd.com 微信第三方登录属…

Android APP微信第三方登录踩坑 - 微信开放平台修改应用包名后微信第三方登录失败

在微信开放平台注册移动应用&#xff0c;才能在APP里实现「微信登录」和「微信支付」。 近期因为业务需要&#xff0c;需要修改应用的包名&#xff0c;因此在微信开发平台重新提交了应用「基本信息」修改申请&#xff0c;顺便吐槽下&#xff0c;现在微信开发平台对应用审核真是…

微信第三方登录redirect_uri 参数错误

微信第三方登录 先说解决方案&#xff1a;redirect_uri 参数错误 在开放平台设置好回调地址&#xff0c;例如地址是 www.niezhiliang.com 那么在生成二维码的时候回调只能写该域名下的地址 在申请二维码页面回调地址(你的redirect_uri) 还必须加上http或者https&#xff0c;…

微信第三方登录接口

随着手机微信的崛起&#xff0c;腾讯发布的微信联登确实很诱惑pc端的伙伴们&#xff0c;现在就说说在pc端用微信扫一扫实现微信第三方登陆的方式。 第一步&#xff1a;获取AppID AppSecret(不做解释&#xff0c;自己去微信公众平台申请) 第二步&#xff1a;生成扫描二维码&…

微信 第三方登录

转自&#xff1a;http://www.cnblogs.com/linjunjie/p/6378166.html#3902595 从http://www.cnblogs.com/v-weiwang/p/5732423.html 申请开发者账号之内的就不累赘了&#xff0c;网上一大堆&#xff1a; 说下需求&#xff0c;一个网页要在三类容器运行&#xff0c;公司app&#…

微信第三方登录

微信第三方登录 步骤&#xff1a; 1.申请你的AppID 请到微信开放平台https://open.weixin.qq.com/注册成为开发者&#xff0c;然后创建应用并提交审核&#xff0c;只有审核通过的应用才能进行开发。 2.下载SDK及API文档 Android Studio环境下&#xff1a; 在build.gradle文件…

流程图了解微信第三方登录

1.首先是&#xff0c;浏览器显示微信登录 2.用户扫描&#xff0c;发送请求到微信服务器&#xff0c;前端也会发送一个请求到自己的后台服务器&#xff0c;后台服务器提供微信服务器获取第三方验证授权地址&#xff0c;携带回调路径 3.微信服务器验证成功&#xff0c;返回code…

Oracle官网下载JDK

进入Oracle官网&#xff1a;https://www.oracle.com/index.html 1、选择support&#xff08;支持&#xff09;software Download 2、选择 java 3、选择jdk 4、拉到底选择java archive&#xff08;档案文件&#xff09; 5、选择要下载的版本

解决JDK官网下载龟速的问题

在JDK的官网下载JDK时还需要登录Oracle 且下载的时候那速度相当缓慢 可以使用华为的镜像下载&#xff0c;超快的 下载仓库地址&#xff1a;x​​​​​​​ Index of java-local/jdk

如何在官网下载java JDK

1.打开Oracle官网&#xff0c;准备下载java JDK (下载时需要使用注册用户登陆&#xff0c;可以免费注册) 官网地址&#xff1a;http://www.oracle.com/ 登录Oracle账号 选择适合自己的JDK版本 选择适合的版本 勾选 下载

JDK1.8u162以及JDK1.8所有历史版本官网下载地址

很多网友想看JDK1.8里面所有的版本&#xff0c;今天我就给大家带来了所以JDK1.8版本的官方下载地址&#xff0c;其中包括Windows版本和Linux版本 JDK1.8所有版本官网下载链接 Java Archive Downloads - Java SE 8 Attention!!! Java Archive | Oraclehttps://www.oracle.c…

JDK 的 ORACLE 官网下载步骤

下面以下载 jdk-8u181-linux-x64.tar.gz 为例&#xff0c;说明下在 ORACLE官网下载的具体步骤 1、进入oracle官网–>Resource–>Software Downloads&#xff0c;如下截图&#xff1a; 2、进入页面后&#xff0c;下滑选择“java”&#xff0c;然后点击“Java(JDK) for De…