资讯动态

NS-2.26仿真器安装与Tcl脚本实战:从编译到trace分析

发布时间:2026/9/29 1:38:00 来源:尧图企业网站定制
简介这是一份网络仿真软件包 ns-allinone 2.26 完整发行版整合了经典网络模拟器 ns-2 及配套组件适合网络专业学生、研究人员及工程师用于学习与实验。该版本重点支持 MAC 层与路由层仿真可构建无线/有线网络场景测试路由策略、QoS、传输控制等协议行为。压缩包内含 5056 个文件总大小约 50.44MB以 tcl 脚本、c/cc/h 源码、测试用例 (test)、nam 动画文件、文档 (tex/html/readme) 等为主覆盖从编译配置到仿真实例的完整体系。已有 108 人学习参考。解压后用户可依据标准流程配置编译运行内置示例场景并观察网络流量、延迟、丢包等输出也可修改源码扩展算法是深入理解网络协议机制与开展仿真研究的实用工具。1. NS-allinone-2.26 到底装了什么为什么二十年老仿真器还有人在用拿到ns-allinone-2.26.tar.gz这个文件时多半意味着你正在复现一篇十几年前论文里的无线网络实验或者被导师要求“用 NS-2 把某某协议跑一下”。这个包解决的是 NS-2.26 本体和它依赖的 Tcl/Tk、OTcl、tclcl、nam、xgraph 一起打包的问题allinone 这个名字名副其实一个 tar.gz 里把能跑通整套仿真环境的所有组件都绑定了。这个版本确实老但老不等于没人用。NS-2.26 至今仍是很多课程、论文复现和技术博客里被点名指定的版本因为大量现成的协议实现和 Tcl 脚本都是按老 API 写的用 NS-3 或者新版 NS-2 反而跑不起来。对还在做 Ad Hoc 网络、无线传感器网络研究的人来说这个包就是他们离不开的工作台。但它有个很现实的问题一套 2005 年左右的 C 代码放在今天的 Linux 发行版上几乎不可能一次编译通过。这篇笔记就说清楚三件事怎么把这套 tar.gz 在能接受的系统上装起来、怎么跑通第一个仿真、以及真正让你浪费时间的高频坑在哪。2. 用 tar.gz 源码包编译 ns-2.26configure/make 三步走与参数选型2.1 为什么 allinone 比逐组件安装靠谱很多人一上来想自己分开装先装 Tcl/Tk再装 OTcl再装 tclcl最后编 NS-2 和 nam。这个思路本身没错但版本配套非常折磨人。NS-2.26 当年绑定的是 Tcl/Tk 8.4.x而现代 Linux 发行版自带的往往是 8.6 甚至更新版本。Tcl 8.6 对解释器初始化和事件循环的接口做了调整NS-2.26 的 otcl 和 tclcl 代码编译能过但运行时经常莫名其妙崩溃或者 nam 启动后立刻闪退报错信息还不直观。allinone 的价值就在这里它把 NS-2.26 当时验证过的组件版本锁死在一个压缩包里。tcl、tk、otcl、tclcl、ns、nam、xgraph 的版本互相匹配编译顺序也是安装脚本编排好的。你只要保证系统里有合适的编译器和 X11 开发库剩下的事情基本自动完成。我一般建议只要手头有这个 allinone 包就不要去拆开装。自己拼版本遇到的那些玄学问题大多是因为某个子组件版本和预期不一致。2.2 编译前的环境检查gcc、make、X11 三个维度先别急着解压花两分钟确认系统环境。以下命令在终端里执行一下gcc --version g --version make --version pkg-config --modversion x11 || echo no x11 dev dpkg -l | grep libxmu-dev第一组命令看编译器版本第二组看 X11 开发库是否存在。NS-2.26 的年代gcc 4.x 是主流代码里用了一些旧的 C 写法。如果你机器上是 gcc 9 以上后面编译大概率会在某个组件的 C 源码上报错这是正常的不是你的操作问题。libxmu-dev这类包是 nam 和 xgraph 编译时要用的 X 窗口工具库。缺少它configure 阶段就会失败错误信息通常是找不到X11/Xlib.h或者-lXmu。提示如果看到X11/Xlib.h: No such file or directory不用去翻 NS 源码直接装 X11 开发包即可。另外安装路径不要带中文、空格和奇怪字符。allinone 的安装脚本会生成一批带相对路径的链接路径里一个空格就能让后续很多命令找不到文件。我一般放在/home/ns/ns-allinone-2.26这种干净目录。2.3 ./install 一条命令完成三层组件的编译与安装把包解压后在ns-allinone-2.26/目录下执行cd /home/ns/ns-allinone-2.26 ./install./install做的事情本质上就是先 configure 再 make 再 make install但顺序是写死的先 tcl、tk然后 otcl、tclcl再 ns最后 nam 和 xgraph。你不用手动介入每个子目录。如果因为某些原因不能跑./install退一步手动操作也行./configure --with-tcl/home/ns/ns-allinone-2.26/tcl8.4.x \ --with-tk/home/ns/ns-allinone-2.26/tk8.4.x make make install注意这里我用8.4.x占位实际目录名以你解压出来的为准ls 看一眼就知道。--with-tcl和--with-tk参数是告诉 configure去哪个目录找 Tcl/Tk 的开发文件allinone 里已经带了这两个包所以路径指向 allinone 内部即可不要指向系统自带的/usr/lib。编译过程会持续十几分钟到半小时。如果中途失败不要重新跑整个 install先看失败的是哪个子目录进入那个目录执行make输出会直接告诉你在哪个文件哪一行出了问题。2.4 环境变量和第一个自检指令编译成功后真正容易翻车的地方才来环境变量。NS-2.26 运行时要加载自己编译出来的动态库这些库不在系统默认路径里你不告诉系统它们在哪儿ns命令就永远提示找不到共享库。我习惯把以下内容写进~/.bashrcexport NS_HOME/home/ns/ns-allinone-2.26 export PATH$NS_HOME/bin:$NS_HOME/tcl8.4.x/unix:$NS_HOME/tk8.4.x/unix:$PATH export LD_LIBRARY_PATH$NS_HOME/otcl-1.x:$NS_HOME/lib:$LD_LIBRARY_PATH export TCL_LIBRARY$NS_HOME/tcl8.4.x/library然后source ~/.bashrc执行两个自检命令ns -v ldd $(which ns) | grep tclns -v正常时会输出 ns-2.26 的版本信息说明主程序能跑起来。ldd检查动态库链接情况如果输出里出现libtcl8.4.so not found说明 LD_LIBRARY_PATH 没写对检查 allinone 目录里 otcl 和 lib 文件夹的真实名称。注意PATH 和 LD_LIBRARY_PATH 写错一个字符症状都是“命令找不到”或“共享库找不到”排查时先 echo 看一遍这两个变量。2.5 编译报错时的参数兜底CXXFLAGS 与编译器降级很多人在 Ubuntu 22.04 以上版本编译 NS-2.26 时会遇到类似‘newer’ is not a member of ‘std’或undefined reference to ‘TclpThreadCreate’的报错。这些本质是编译器版本太新老代码用了已经不存在的标准库接口。常见的解决办法有两个。第一是降级编译器安装 g-4.8 并用CXXg-4.8加进 configure 环境第二是调低 C 标准并加兼容宏make clean CXXFLAGS-stdc03 -DUSE_MEMCPY1 ./install-DUSE_MEMCPY1是 NS 社区流传很广的一个开关用来绕开老代码和现代编译器在字符串拷贝上的冲突。如果你的系统没到 gcc 11 那么激进这个参数通常够用如果问题依旧就去装老编译器别跟源码较劲。3. 跑通第一个 ns-2.26 仿真写 Tcl 脚本、调 nam、读 trace 文件3.1 从零写一个双节点无线 Tcl 脚本NS-2 的仿真脚本是 Tcl 写的先说清楚一件事不要自己从空白文件手敲全部配置。NS-2 的无线模块有太多前置设置漏一个create-god都跑不动。下面的脚本是一个最小双节点 Ad Hoc 仿真可以直接保存为wireless.tcl运行。# 无线场景配置 set val(chan) Channel/WirelessChannel set val(prop) Propagation/TwoRayGround set val(netif) Phy/WirelessPhy set val(mac) Mac/802_11 set val(ifq) Queue/DropTail/PriQueue set val(ll) LL set val(ant) Antenna/OmniAntenna set val(x) 500 set val(y) 500 set val(stop) 50.0 set ns [new Simulator] set tf [open out.tr w] $ns trace-all $tf set nf [open out.nam w] $ns namtrace-all-wireless $nf $val(x) $val(y) set topo [new Topography] $topo load_flatgrid $val(x) $val(y) create-god 2 set chan_1_ [new $val(chan)] # 节点配置 $ns node-config -adhocRouting DSDV \ -llType $val(ll) \ -macType $val(mac) \ -ifqType $val(ifq) \ -ifqLen 50 \ -antType $val(ant) \ -propType $val(prop) \ -phyType $val(netif) \ -channel $chan_1_ \ -topoInstance $topo \ -agentTrace ON \ -routerTrace ON \ -macTrace OFF set node_(0) [$ns node] set node_(1) [$ns node] # 节点初始位置与移动 $node_(0) set X_ 100.0 $node_(0) set Y_ 100.0 $node_(0) set Z_ 0.0 $node_(1) set X_ 400.0 $node_(1) set Y_ 400.0 $node_(1) set Z_ 0.0 $ns at 1.0 $node_(0) setdest 200.0 300.0 20.0 $ns at 2.0 $node_(1) setdest 300.0 100.0 20.0 # 建立 UDP 流量 set udp0 [new Agent/UDP] set null0 [new Agent/Null] $ns attach-agent $node_(0) $udp0 $ns attach-agent $node_(1) $null0 $ns connect $udp0 $null0 set cbr0 [new Application/Traffic/CBR] $cbr0 set packetSize_ 512 $cbr0 set interval_ 0.2 $cbr0 attach-agent $udp0 $ns at 1.0 $cbr0 start $ns at 49.0 $cbr0 stop # 结束 $ns at $val(stop) stop $ns at $val(stop) puts \sim done\ $ns at $val(stop) $ns halt $ns run这个脚本里值得关注几个参数。interval_ 0.2表示每 0.2 秒发一个包packetSize_ 512 是 512 字节两者共同决定流量速率。DSDV 是路由协议换成 AODV 或 DSR 也只需要改这一处字符串。create-god 2的 2 必须等于节点数少了运行时会提示找不到 god 对象。运行方式很简单ns wireless.tcl结束后目录下会生成out.tr和out.nam两个文件。前者是文本格式的 trace 记录后者是 nam 动画的输入文件。3.2 用 awk 把 trace 读成指标丢包率、吞吐量out.tr是一个纯文本事件日志每一行记录一个事件格式大概是事件类型、时间、源节点、目标节点、层级、标志位……对刚接触的人来说这堆数字像天书但用 awk 可以很快提取出关键指标。统计丢包率的命令awk $1s $4AGT {sent} $1r $4AGT {recv} $1d $4AGT {drop} END {printf sent%d recv%d drop%d loss%.2f%%\n, sent, recv, drop, (sent-recv)/sent*100} out.trs是发送事件sendr是接收事件received是丢弃事件drop。$4AGT表示只看应用层避免把 MAC 层重传、路由层控制包都算进来。这个过滤条件很重要不改的话统计出来的丢包率会偏低因为大量被 MAC 层重传成功的包不算丢。3.3 用 nam 可视化能回放不代表协议对nam 是 NS-2 自带的动画播放工具运行nam out.nam你会看到两个节点按设定的 setdest 移动UDP 数据包在中间传递丢包时会出现红色的丢弃标记。nam 适合快速看网络拓扑和移动模型设计是否合理但注意一个坑动画流畅不代表协议行为正确。比如 DSDV 路由不稳定时包会频繁改路nam 里看起来只是路径切换但 trace 文件里可能已经出现了很多次!!的转发失败记录。所以我习惯先跑一遍 awk 统计再打开 nam 确认现象顺序反过来容易被动画误导。4. ns-allinone 安装与运行的 5 个高频坑现象、原因、解决4.1 编译死在 C 标准库接口上现象编译到 ns-2.26 本体时终端刷出一屏error: ‘newer’ is not a member of ‘std’或者链接阶段报undefined reference to ‘TclpThreadCreate’。原因系统默认 gcc/g 版本太新。NS-2.26 的代码基于 C98 时代的 STL现代编译器做了大量接口清理和废弃老代码踩中一两个就停摆。解决先试CXXFLAGS-stdc03 -DUSE_MEMCPY1 ./install还不行就装老编译器比如 Ubuntu 上用apt install g-4.8再用CXXg-4.8重新 configure。不要试图手工改源码老代码互相调用关系复杂改一处往往牵出三处新错。4.2 运行 ns 提示找不到 libtcl8.4.so现象编译全部成功但执行ns wireless.tcl时立即报错error while loading shared libraries: libtcl8.4.so.0: cannot open shared object file。原因tcl 的动态库路径没有加进 LD_LIBRARY_PATH。allinone 编译出来的 tcl 库放在自己目录里不被系统默认搜索而ns二进制在运行时才去找它。解决确认$NS_HOME/tcl8.4.x/unix或$NS_HOME/lib下存在libtcl8.4.so然后把对应目录写进 LD_LIBRARY_PATH。用ldd $(which ns)检查直到输出不再有not found。4.3 新终端里 ns 又“消失”了现象上一秒还能跑ns -v关掉终端重新打开又提示command not found。原因环境变量只写在了当前终端的会话里没有持久化到 shell 配置文件。解决把 2.4 节的环境变量追加进~/.bashrc然后执行source ~/.bashrc。这里有个细节不要只加 PATHLD_LIBRARY_PATH 和 TCL_LIBRARY 也必须一起加否则会出现命令找得到但库找不到的割裂状态。4.4 麒麟 V10 这类系统缺 X11 开发包现象configure 阶段报错X11/Xlib.h: No such file or directory或者 nam 编译时找不到-lXmu。这个场景在麒麟 V10 这类国产 Linux 系统上尤其常见默认安装通常不带完整开发环境。原因系统只装了运行库没装编译期需要的 dev 包。X11 相关头文件属于libX11-dev、libxmu-dev、libxt-dev这些包。解决能联网就直接装开发包。对离线内网环境我一般先把需要的 tar.gz 包推到内网私有仓库再通过软件源分发到各台机器。这个推包动作可以借助 KubeKey 这类离线部署工具完成它能把本地 tar.gz 制作成私有仓库可识别的格式这样同一个 allinone 包就能在多台机器上重复安装不用每台都手工传文件。关键点是开发包齐了configure 基本能一次过。4.5 nam 打开动画闪退或无响应现象nam out.nam启动后窗口一闪而过或者弹出错误couldnt read file library/...。原因两个方向。第一是 nam 依赖的 Tk 库路径不对导致界面初始化失败第二是没有图形显示环境比如你用 SSH 连服务器跑。解决确认 LD_LIBRARY_PATH 包含 tk 的 unix 目录远程环境用Xvfb :99 -screen 0 1024x768x24 起虚拟显示再export DISPLAY:99nam 就能在无头环境下跑起来。注意 nam 的动画导出也可以走这个虚拟显示方案批量导出时很实用。5. 把 ns-2.26 装进 Docker批量仿真与 awk 解析 trace 的技巧5.1 用老镜像把 allinone 做成可重复运行的环境新系统上装 NS-2.26 的痛本质是编译器和库版本代差太大。我现在所有 NS-2.26 工作都放进 Docker宿主环境保持干净换机器也能复现。准备一个 DockerfileFROM ubuntu:14.04 RUN apt-get update apt-get install -y gcc g make \ xorg-dev libxmu-dev libxt-dev COPY ns-allinone-2.26.tar.gz /opt/ WORKDIR /opt RUN tar xzf ns-allinone-2.26.tar.gz \ cd ns-allinone-2.26 ./install ENV PATH/opt/ns-allinone-2.26/bin:$PATH ENV LD_LIBRARY_PATH/opt/ns-allinone-2.26/otcl-1.x:/opt/ns-allinone-2.26/lib:$LD_LIBRARY_PATH CMD [ns, -v]选 ubuntu:14.04 而不是最新版是因为它自带的 gcc 4.8 和老代码兼容性最好。构建时只需docker build -t ns226 .运行仿真时用docker run -it -v $PWD/sim:/sim ns226 bash把本机 sim 目录挂载进容器Tcl 脚本放在这个目录里容器内外共享非常利于批量处理。5.2 批量跑参数扫描把速率、种子循环起来做仿真最常干的事就是改参数看趋势。手工改 Tcl 脚本里的 interval_ 再一个个跑又慢又容易漏改文件名。我一般用 sed 生成脚本副本for rate in 100 200 400 800; do sed s/interval_ 0.2/interval_ 0.1/ wireless.tcl run_${rate}.tcl ns run_${rate}.tcl mv out.tr res_${rate}.tr done这个循环只演示了最简单的替换逻辑实际上可以把 seed、节点数、发包速率全部参数化。关键是每次运行完后立刻把 out.tr 改名归档否则下一轮仿真会覆盖上一轮结果。5.3 结果验证的土办法换 seed 重跑看数字漂移NS-2.26 的移动模型和随机数都有种子控制但很多人在脚本里没显式设置导致每次运行结果看似相同其实随机数序列在变。验证结果是否稳定我会用同一套参数换 seed 跑三遍然后比较丢包率的波动范围。用一行 awk 把丢包率统计到 CSVfor f in res_*.tr; do awk -v name$f $1s $4AGT {s} $1r $4AGT {r} END {printf %s %.2f\n, name, (s-r)/s*100} $f done result.csv三遍跑下来如果丢包率的波动在 5% 以内说明趋势可信波动大就加大仿真时长或换更大场景别急着下结论。我现在装任何 NS-2.26 源码包都默认先进 Docker编译参数写成注释放在 Dockerfile 旁边避免两个月后自己也忘了当初是怎么跑通的。希望这些经验对你拿到 tar.gz 包后能少走一段弯路特别是那些看起来像玄学的编译问题其实大多能找到明确出处。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑