NS-2网络仿真环境搭建:ns-allinone-2.26安装配置与trace分析实战
简介ns-allinone-2.26 是经典开源网络仿真软件套件集成 ns-2 模拟器与多种扩展模块面向网络协议分析、MAC 层与路由层建模研究主要供高校网络课程教学、科研项目验证以及网络工程师进行方案预演使用。压缩包内共包含 5056 个文件整体容量约 50.44MB核心内容以 tcl 仿真脚本、C/C 协议源码、头文件、测试用例和 nam 可视化脚本为主并随附文档、示例场景与编译配置工具可支持有线网络、无线自组网、路由协议、组播通信等不同层次场景的仿真模拟。目前已有 108 人学习下载适用范围较广。其中包含完整源码树、配置脚本和大量仿真场景既能运行自带场景观察吞吐量、时延、丢包率等性能指标也能通过修改 MAC 层与路由层参数深入理解协议运作机制是网络仿真入门学习与科研分析的一套实用工具。1. ns-allinone-2.26这个 2005 年的安装包为什么今天还有人翻出来如果你的课程作业、毕业设计或者论文复现里出现了 ns-allinone-2.26 这几个字那大概率不是你自己选的老古董而是导师或者课程大纲点名指定的环境。NS-2 是网络仿真里绕不开的经典工具而 ns-allinone-2.26 是它比较完整的一套全家桶分发包一次把 ns-2.26、nam、tcl/tk、otcl、xgraph 这些组件全部给你编译好。说白了它解决的就是「我要在 Linux 上跑网络仿真但不想一个个源码去拼环境」的问题。别被它的年份吓退我见过不少 2024 年的论文复现清单里仍然写着 ns-allinone-2.26很多高校实验室的仿真平台至今还在用这套东西。适合读这篇文章的人有两类一类是刚拿到任务、连 configure 都没跑过的新手你需要知道从解压到跑出第一个 trace 文件的完整路径另一类是在 64 位新系统上折腾半天编译不过的老手这里有几条能直接救命的参数和坑。下面按我实际跑通的过程来讲。2. 编译安装configure 之前先解决 gcc 版本和 32 位库2.1 环境准备不是所有 Linux 都能直接编这个包ns-allinone-2.26 的年代远早于 Ubuntu 18.04 之后的系统它对编译器、库文件的假设都是基于 2005 年前后的 X11 和 gcc 生态。我最开始在一台 Ubuntu 22.04 上直接解压跑 ./install结果 configure 阶段就报了一堆错不是找不到这个头文件就是链接不到那个库。后来换个思路老老实实把依赖装齐编译才顺下去。建议先在干净的 Ubuntu 16.04 或 CentOS 6 虚拟机里做如果你只能在新系统上跑先把下面这些包装好sudo apt-get update sudo apt-get install -y build-essential g gcc make perl sudo apt-get install -y libxt-dev libx11-dev libxmu-dev libxpm-dev sudo apt-get install -y x11proto-core-dev libxtst-dev提示libxmu-dev 和 libxt-dev 是关键。NS-2.26 的 nam 组件依赖 X11 的 Xt 和 Xmu 库缺了它们会在 make 阶段报cannot find -lXmu或Xt.h not found。gcc 版本是另一个隐形门槛。ns-2.26 的源码是用老式 C 写的对 gcc 4.8 之后的新标准适配很差。Ubuntu 16.04 自带的 gcc 5.4 勉强能编Ubuntu 18.04 的 gcc 7.5 就得碰运气。我试过用 gcc 4.8 编 2.26 是可行的gcc 版本再往上编译错误会多到你怀疑人生。2.2 解压与 configure关键在 config 文件的路径继承拿到 ns-allinone-2.26.tar.gz 之后解压路径最好不要带中文和空格目录层级也别搞太深。我一般放在/home/user/ns这种平级目录后面环境变量写起来省事。解压命令没有玄学tar 一把过重点在于整个包的 configure 顺序。cd ~/ns tar -xzvf ns-allinone-2.26.tar.gz cd ns-allinone-2.26 ./install./install会依次进入 tcl/tk/otcl/tclcl/ns-2.26/nam-1 等子目录自动执行各自的 configure 和 make。你要留意的是终端输出里每一步是否出现OK字样我踩过的坑是前几个组件都过了编译到 nam-1 才挂掉但 install 脚本不会停最后看总结文件时才发现 nam 没有编出来。如果中途断了不要急着重新跑 install先切到对应子目录手动补编译cd nam-1 ./configure --with-tclcl/home/user/ns/ns-allinone-2.26/tclcl \ --with-tcl/home/user/ns/ns-allinone-2.26/tcl-8.4.14 \ --with-tk/home/user/ns/ns-allinone-2.26/tk-8.4.14 make clean make这里--with-tclcl和--with-tcl手动指定了依赖路径是为了让 nam 找到刚编译出来的 tclcl 库和 tcl 头文件。install 脚本在自动模式下偶尔会有路径继承丢掉的毛病手动补的时候把路径写绝对成功率最高。3. 环境变量与第一个 TCL 脚本从一行 NS2 命令到拿到 trace 文件3.1 环境变量配置这一步漏了ns 命令会直接报错找不到编译全部通过后ns-allinone-2.26 目录下会生成几个关键的二进制文件包括ns-2.26/ns、nam-1/nam、tcl8.4.14和tk8.4.14的库目录。这时候你执行ns命令shell 是找不到的因为可执行文件不在 PATH 里。export PATH$PATH:/home/user/ns/ns-allinone-2.26/ns-2.26:/home/user/ns/ns-allinone-2.26/nam-1:/home/user/ns/ns-allinone-2.26/tcl8.4.14/unix:/home/user/ns/ns-allinone-2.26/tk8.4.14/unix export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/home/user/ns/ns-allinone-2.26/tcl8.4.14/unix:/home/user/ns/ns-allinone-2.26/tk8.4.14/unixPATH里加的是 ns、nam、tcl/tk 可执行文件所在目录缺了 ns 会提示 command not found缺了 nam 则 nam 无法从命令行启动。LD_LIBRARY_PATH是运行时的动态库搜索路径。ns 运行时要加载 libtcl8.4.so 和 libtk8.4.so不配的话会报error while loading shared libraries。这两个变量每次开新终端都得重新 source所以我习惯把它写进.bashrc结尾追加一行source ~/ns/ns-allinone-2.26/env.sh把上面两段 export 存成 env.sh一劳永逸。3.2 最小仿真脚本两个节点一条链路先把数据流跑起来环境配好后验证安装是否真的好使不是去翻 README而是直接写一个最小的 TCL 脚本跑一遍。这个脚本做的是创建两个节点用一条 1Mbps 的丢包链路连接UDP 业务从 node0 发到 node1仿真持续 1 秒。set ns [new Simulator] set tracefd [open out.tr w] $ns trace-all $tracefd set namfd [open out.nam w] $ns namtrace-all $namfd set n0 [$ns node] set n1 [$ns node] $ns duplex-link $n0 $n1 1Mb 10ms DropTail $ns queue-limit $n0 $n1 10 set udp0 [new Agent/UDP] $ns attach-agent $n0 $udp0 set cbr0 [new Application/Traffic/CBR] $cbr0 set packetSize_ 500 $cbr0 set interval_ 0.01 $cbr0 attach-agent $udp0 set null0 [new Agent/Null] $ns attach-agent $n1 $null0 $ns connect $udp0 $null0 $ns at 0.1 $cbr0 start $ns at 0.9 $cbr0 stop $ns at 1.0 finish proc finish {} { global ns tracefd namfd $ns flush-trace close $tracefd close $namfd exit 0 } $ns run这里每个对象都有存在的理由Simulator是所有仿真逻辑的总控duplex-link是双向链路带宽 1Mb、传播时延 10ms队列类型选 DropTail这就是常见做法里的默认配置queue-limit把队列上限压到 10是为了让后续拥塞丢包现象可观察CBR 业务固定包长 500 字节、每 10ms 发一个包差不多 400kbps 的发送速率配合 1Mb 链路不至于瞬间打满。跑法同样直接cd ~/ns ns 1test.tcl ls -l out.tr out.nam如果终端没有反馈且两个文件都生成了说明 ns 能正常工作。接下来就可以干正事——解析 trace。4. 看透 trace 文件用 awk 把丢包率和吞吐量抠出来4.1 trace 格式逐列拆解每个数字都不是摆设out.tr 里每一行是一条事件记录格式在 ns-2.26 里是固定 12 列。我新手阶段最吃亏的地方就是拿 Excel 打开 trace 文件硬数列等搞明白每一列的含义后awk 处理就水到渠成了。 0.1 0 1 cbr 500 0 0 0.0 0.1 1 5 - 0.1 0 1 cbr 500 0 0 0.0 0.1 1 5 r 0.11005 1 0 cbr 500 0 0 0.0 0.1 1 5 d 0.2 0 1 cbr 500 0 0 0.0 0.1 1 6从左到右依次是事件类型、仿真时间、源节点、目标节点、包类型、包大小、flags、flow id、源地址、目的地址、序列号、包唯一 id。事件类型常见四个字符表示入队、-表示出队、r表示接收、d表示丢弃。这些字符是后续所有统计脚本的判词。用 awk 统计丢包率是每个 NS-2 用户都绕不过去的基本功。比如我对上面 1 秒仿真里的发出的包和丢弃的包做个计数echo 发送包数: grep ^ out.tr | wc -l echo 丢弃包数: grep ^d out.tr | wc -l echo 接收包数: grep ^r out.tr | wc -lgrep ^匹配的是入队事件每发一个包就产生一次入队记录所以数量等于发送包数。grep ^d是丢弃事件。丢包率 丢弃数 / 发送数你可以自己再除一下。接收包数对应r事件。尾部那一列是包的唯一 id可以配合-t时间列做端到端时延统计不过那是后话。先把丢包这个最基本的指标算明白再做吞吐量不迟。4.2 一个 awk 脚本同时统计丢包率和吞吐量上面的 grep 是分步看的实际做仿真实验时通常几十组参数要批量跑手动 grep 效率太低。我一般写一个 awk 一把梭awk {if ($1) send; if ($1d) drop; if ($1r) recv} END {printf send%d drop%d recv%d\n, send, drop, recv} out.tr这个 awk 的写法是把三类事件分别计数$1取第一列事件类型最后在 END 块里打印结果。统计吞吐量的话按接收事件累加包大小再除以仿真时间awk {if ($1r) total $6} END {printf throughput%.2f kbps\n, total*8/1000/1.0} out.tr这里的$6是包大小字节乘以 8 变成比特除以 1000 变 kbps再除以仿真时长 1.0 秒。如果你的仿真时长不是 1 秒把 1.0 换成$8对应的仿真结束时间或直接写死你脚本里的 duration 值。5. 避坑指南ns-allinone-2.26 在新时代的五个典型翻车现场5.1 make 报错cannot find -lXmu现象编译到 nam-1 时链接阶段报ld: cannot find -lXmu整个安装中断nam 没有生成。原因nam 的可视化界面依赖 XmuX11 Misc Utilities库这个库在新系统里不会默认安装Ubuntu 自带的 xorg 不包含它。解决装libxmu-dev和libxt-dev然后回到 nam-1 目录重新 configure 并 make。如果装完还报同样的错检查一下/usr/lib/x86_64-linux-gnu下有没有libXmu.so没有就建一个软链接指向libXmu.so.6。5.2 configure 报错Tcl is not found但 tcl 目录就在隔壁现象otcl 或 tclcl 的 configure 脚本提示找不到 Tcl 的头文件或者版本不匹配明明 ns-allinone-2.26 目录下已经编译出了 tcl8.4.14。原因configure 默认搜索 /usr/local 和系统路径不会自动去看 ns-allinone-2.26 子目录里的私有 tcl它以为你要用系统级 tcl 库。解决手动给 configure 传--with-tcl/home/user/ns/ns-allinone-2.26/tcl8.4.14这类参数或者干脆在./install之前先sudo make install把 tcl 装到系统路径里。我一般倾向手动传参不污染系统。5.3 ns 启动报error while loading shared libraries: libtcl8.4.so现象ns 命令能执行但提示找不到 libtcl8.4.so无法加载动态库。原因编译成功只是链接时找到了库运行时动态加载还需要LD_LIBRARY_PATH指向库文件所在目录。很多人只导出 PATH 忘了导出 LD_LIBRARY_PATH。解决按 3.1 节里的方式把 tcl 和 tk 的 unix 子目录加进 LD_LIBRARY_PATH。注意 64 位系统上还要确认库是 64 位编译的如果是从旧机器拷贝的 32 位库依然会加载失败。5.4 nam 打开 trace 文件一片空白或直接闪退现象nam out.nam能启动图形界面但画布上没有节点或者点开几秒就崩。原因nam 启动后找不到已经编译的 ns 组件对应库或者 out.nam 里的格式与 nam 版本不匹配。ns-allinone-2.26 里的 nam 是配套 ns-2.26 的如果你用新版 nam 去读也容易白屏。解决确认只用包内自带的 nam-1不要从其他 NS-2 版本拷贝 nam 替换。检查 out.nam 是否非空内容里是否包含nodes关键字。我遇到的闪退案例最后定位是因为没设置 DISPLAY 环境变量在纯 SSH 终端里跑 nam 自然会崩。5.5 新 gcc 编译 ns-2.26 时大量template报错现象编译 ns-2.26 主程序时报各种 C 模板语法错误主要集中在link-state和routing相关源码文件。原因ns-2.26 的底层用了老式 C 模板写法新版编译器对模板默认参数和连写解析规则收紧导致语法兼容性崩了。解决换 gcc 4.8 或更低版本。Ubuntu 16.04 自带 gcc 5.4 勉强能用再往上基本没法编。如果你的宿主系统是 Ubuntu 20.04 以上的在虚拟机里直接降级 gcc 比挣扎源码快得多。6. 进阶用法批量仿真与自动提取实验数据的一次性脚本当你跑通单组仿真后真实实验不会有只跑一组的情况。比如要对比不同丢包率下的吞吐量变化常见做法是循环生成 TCL 脚本每组参数跑一个 out.tr再用 awk 自动汇总。这里先写一个改链路丢包率的循环for loss in 0 1 2 5; do sed s/1Mb 10ms DropTail/1Mb 10ms RED/g base.tcl run_$loss.tcl sed -i s/set interval_ 0.01/set interval_ 0.0$loss/ run_$loss.tcl ns run_$loss.tcl awk {if ($1r) total $6} END {print $loss, total*8/1000} out.tr result.txt done这段代码的逻辑是先用 sed 模板替换生成参数不同的脚本然后跑仿真最后 awk 从 out.tr 里抽出接收字节总数换算成 kbps 累加进 result.txt。注意 sed 里的$loss通过引号拼接实现可变值替换awk 里的单引号嵌套也是同样的思路。这个循环跑完后result.txt 里就是不同参数下的对照结果可以直接喂给 gnuplot 画曲线。参数替换的时候有个小坑TCL 脚本里的浮点数格式不能乱改比如interval_ 0.01改成0.001可以直接 sed但改成0.0$loss时要确保 loss 是 1 位数否则会拼出0.01和0.005这种不对称间隔。我一般的处理方式是 loss 用seq 0 1 10生成再在 awk 里除以 1000避免格式翻车。再多说一个验证技巧跑完批量仿真后不要急着信数据。把每组参数对应的 out.tr 用wc -l看一遍如果某组的记录行数突然少了一个量级那基本是脚本生成时链路参数被 sed 误替换了不是真的网络行为。我吃过一次亏一组丢包率下 CBR 包大小被替换成了 5000 字节导致吞吐量暴涨当时还以为发现了什么新现象后来核 trace 才发现是 sed 把packetSize_也捎带改了。从那以后我每次批量仿真前都强制走一遍所有生成脚本里packetSize_和interval_的 grep 检查再交出去。这个习惯让我少返工很多次也分享给你希望帮到你。本文还有配套的精品资源点击获取