☰
ns-allinone-2.26安装避坑指南:Ubuntu下编译NS-2.26网络仿真环境
2026/10/10 17:27:26 网站建设 项目流程

简介:NS-allinone-2.26是一套集成式网络仿真软件包,专为网络协议研究、课程教学与仿真实验设计,帮助用户在不依赖真实硬件的情况下模拟MAC层、路由层等机制,观察数据包转发、延迟、丢包等行为。压缩包共5056个文件、约50.44MB,核心内容以tcl脚本(仿真场景与配置)、cc/c/h源文件(协议模块实现)、tex/html文档(使用说明)为主,同时包含大量测试脚本、nam动画文件、示例拓扑及编译工具脚本。解压后可获得完整的ns-2.26开发环境,包括源代码、configure与Makefile、文档和典型场景,可直接配置编译,并在此基础上修改协议或设计新实验。已有108人学习,适合网络初学者构建基础认知,也适合研究人员借助其可扩展架构验证路由算法、无线通信、QoS等方向的想法。

1. 为什么 2025 年我还要翻出 ns-allinone-2.26 来装

如果你今天在搜索引擎里敲ns-allinone-2.26.tar.gz这串字符,大概率是要给某个课程作业、毕业论文或者老旧仿真项目搭环境。NS-2 这个网络仿真器在学术圈的地位有点像老手艺:新东西层出不穷,但一到移动自组网、TCP 拥塞控制、无线传感器网络这些经典课题,导师和论文模板还在用 NS-2.26 的结果做对比。ns-allinone-2.26是官方把 ns-2.26、nam 动画工具、tcl/tk 脚本库、otcl 语言绑定、xgraph 绘图等一整套组件打包成一个压缩包的产物,解压后就能在 Linux 上从头编译出完整可用的仿真环境。这篇文章就是把我自己装这个老古董的过程、踩过的坑以及怎么让它跑起来的路数完整拆给你,目标是让你少走弯路,两小时内在现代 Linux 发行版上复现出一个能交差的 NS-2.26 环境。

说实话,装 ns-allinone-2.26 不难,难的是它活在 2005 年的编译环境下,跟今天的 GCC、Tcl/Tk、X11 库有大量兼容性摩擦。我在 Ubuntu 22.04 和 CentOS 7 上都踩过完整的坑,从gcc-3.4找不到到otcl编译报错,再到 nam 启动黑屏,每个坑都有对应的解法和性价比评估。适合谁的场景也很明确:你必须跑 NS-2 的课程设计、毕业论文复现、或者读实验室祖传代码的人。如果你只是想快速搭个网络仿真环境并且没有历史包袱,那直接去学 ns-3 或 OMNeT++ 更省心。但如果你已经被标题里的ns-2.26锁定了,那就跟我把这套流程走完。

2. 理解 ns-allinone 的结构:先搞清楚你拿到的是什么黑匣子

2.1 allinone 到底打包了哪些组件

ns-allinone-2.26.tar.gz解压后,你会发现它不是一个单一软件,而是一整套工具链的集散地。典型目录结构包括ns-2.26(仿真主程序)、nam-1.11(网络动画可视化工具)、tcl8.4.5(Tcl 脚本语言运行时)、tk8.4.5(Tk 图形工具包)、otcl-1.0(面向对象的 Tcl 扩展)、tclcl-1.14(Tcl 到 C++ 的粘合层)、xgraph-12.1(绘图工具)以及libpng、zlib等依赖库。这个结构不是随便堆的,NS-2 的架构决定了你写仿真脚本用 Tcl,底层调度和协议实现用 C++,而otcl和tclcl就是连接两者的桥梁,nam 则负责把 trace 文件变成可以播放的动画。

理解这个结构对你后面排错至关重要。最常见的错误是只装了 ns-2.26 本体,却忽略了 tcl/tk 的版本匹配问题。我在第一次接触时,天真地以为只需要把ns命令跑通就行,结果 nam 一直打不开,排查下来才发现tk8.4.5编译时缺了 X11 开发库,动画工具没装上。所以只要你是从ns-allinone-2.26.tar.gz这个包开始,我强烈建议把这些组件都编译完,而不是只挑主程序编译。每个组件之间有依赖顺序,从底层库往上装才是正路。

2.2 版本选型:为什么死守 2.26 而不是用更新的版本

在动手装之前,你先要回答一个问题:为什么很多人筛出的是ns-allinone-2.26、ns-2.26而不是 ns-2.35(官方生命周期最后一版)?答案很现实:你的目标场景是新版本跑不了的。举个例子,很多 IEEE 论文里的 AODV、DSDV 仿真数据是在 NS-2.26 或 NS-2.28 上跑的,如果你换到 2.35,协议行为有细微差异,数据就对不上了。而且 2.26 这个版本在教学领域有大量现成的 Tcl 脚本资源,课程设计里大家都用它,遇到问题搜一圈就有答案。相比之下,2.34、2.35 的社区问答密度低得很。

我一般给学生的建议是:如果是新开题,用 2.35 更稳;如果你是复现某个 2.26 场景或跟导师项目走,就用 2.26。我在一个无线传感器网络项目中就是被逼着回到 2.26 的,因为组里师弟的脚本写的是Mac/802_11的旧式参数格式,在高版本里直接解析报错。别小看导火索,这类细节会吞掉你半天时间。

2.3 最小系统的硬件与操作系统要求

ns-allinone-2.26不需要高性能机器,单核 CPU 加 1GB 内存都能跑,但它对操作系统很挑剔。常见做法是使用 Ubuntu 16.04 或 18.04 这类相对旧的发行版,编译成功率最高。如果你只有 Ubuntu 20.04 以上或者 Fedora 这类新系统,也不是没有活路,但要解决 GCC 版本兼容和库缺失的问题,我会在第三章和第五章详细讲。虚拟机里跑一个 Ubuntu 18.04 镜像是我最推荐的路子,因为隔离性好、快照后悔药方便,坏了就还原。

3. 在 Ubuntu 上编译安装 ns-allinone-2.26:从解压到能用的完整操作

3.1 准备编译环境:依赖包一次装齐

在 Ubuntu 系统上编译 NS-2.26,先把编译工具链和依赖库装齐。下面是 Ubuntu 18.04 和 20.04 通用的一套命令:

sudo apt-get update sudo apt-get install -y build-essential gcc g++ make sudo apt-get install -y libxt-dev libxext-dev libx11-dev libxmu-dev sudo apt-get install -y libpng-dev zlib1g-dev sudo apt-get install -y xgraph nam

第一行的build-essential会带上 gcc、g++、make 等基础编译工具;第二行是 Tk 图形界面编译必需的 X11 开发头文件,没有它们 tk8.4.5 会直接 configure 失败;第三行的libpng-dev和zlib1g-dev是 nam 和 xgraph 的依赖。这里有个小细节:Ubuntu 18.04 默认 gcc 版本是 7.x,NS-2.26 的 C++ 代码和 TclCl 库编译会报错,所以后面要处理降级问题。如果你用的是 Ubuntu 22.04,gcc 11 的报错更多,建议直接上 Docker 容器跑 Ubuntu 16.04 镜像,网上的现成镜像也不少。

参数说明:这些 apt 包名在 Ubuntu 各版本之间有微调,例如 20.04 里libpng-dev替换了老版的libpng12-dev,但作用都是一样的——提供 PNG 读写的头文件和链接库。装完依赖后可以用dpkg -l | grep libxt-dev确认关键包已安装。

3.2 解压与 configure:注意路径不要带中文和空格

依赖备齐后,把压缩包放到家目录下解压并进入目录:

cd ~ tar xzf ns-allinone-2.26.tar.gz cd ns-allinone-2.26 ./install

这里有个最常见翻车点:tar xzf解压后一定要看一眼目录名,是不是真的是ns-allinone-2.26。有的早期下载包解压后目录名可能是ns-allinone-2.26,如果写错了,后面所有相对路径都错。./install是个大 shell 脚本,它会按顺序自动进入各个子目录执行 configure 和 make,全程大约 15 到 30 分钟,取决于你那台机器。脚本执行期间终端会刷大量输出,看到某个子目录提示make: *** [otcl] Error 1这类信息不要慌,先让其跑完,再根据最后的日志定位。

值得单独一提的是路径问题。ns-allinone-2.26对路径里的空格、括号、中文等字符是敏感的,因为 configure 脚本生成的 Makefile 对路径有硬编码,一旦解压路径带空格,后面的otcl编译必挂。我实验室一台 Windows 虚拟机里把包放在C:\Users\张三\桌面\ns-allinone-2.26,用 Samba 挂到 Ubuntu 编译时各种诡异报错,最后换到/home/下就一次过了。所以第一步先把包挪到纯英文路径下,这算是血泪经验。

3.3 编译中途报错的定向修复:otcl 与 tclcl 的典型故障

既然 2.26 在 20.04 以上系统编译时几乎必然报错,那就直接说怎么改。最常见的报错出现在otcl-1.0编译阶段,错误信息类似:

In file included from otcl.c:46: /usr/include/c++/9/new: 202: error: placement new taking a const T& argument is ill-formed

根因是libstdc++高版本移除了旧式的 placement new 表达式,而 otcl 的代码用的是上世纪九十年代的写法。解决办法是给 CXXFLAGS 加宏定义,或者打补丁。

cd otcl-1.0 ./configure --with-tcl=/home/user/ns-allinone-2.26/tcl8.4.5 --with-tk=/home/user/ns-allinone-2.26/tk8.4.5 make clean make CXXFLAGS="-DUSE_CPLUS_NEW -Wno-register -fpermissive" cd ..

这里我把 configure 的路径参数按你自己的绝对路径替换。-DUSE_CPLUS_NEW是让它用新式 new 语义,-fpermissive是把部分报错降级为警告。我一般还会加上-Wno-register关掉register关键字的过时警告。整个 otcl 修完后再回到 ns-allinone 根目录,注释掉install脚本里已经成功的部分,继续执行./install。

另一个高频翻车点在tclcl-1.14,会报tcl8.4.5/generic/tcl.h: no such file or directory。原因是 configure 找不到你刚编译出来的 tcl 头文件。解决办法就是显式指定路径,我通常用--with-tcl=$PWD/../tcl8.4.5和--with-tk=$PWD/../tk8.4.5,这样无论包挪到哪个绝对路径都不怕。

3.4 环境变量配置:ns 命令必须全局可见

编译全部通过后,./install会打印一段提示,告诉你需要设置LD_LIBRARY_PATH和PATH。我把自己的配置写给你参考:

export PATH=$PATH:$HOME/ns-allinone-2.26/bin:$HOME/ns-allinone-2.26/tcl8.4.5/unix:$HOME/ns-allinone-2.26/tk8.4.5/unix export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/ns-allinone-2.26/tcl8.4.5/unix:$HOME/ns-allinone-2.26/tk8.4.5/unix:$HOME/ns-allinone-2.26/otcl-1.0:$HOME/ns-allinone-2.26/lib

这段配置写入~/.bashrc后执行source ~/.bashrc生效。注意LD_LIBRARY_PATH的顺序,把tcl8.4.5/unix和otcl-1.0放前面是关键,因为 ns 启动时要加载 libtcl8.4.so、libotcl.so 这些动态库,如果系统里有别的版本 tcl(比如 tcl8.6),顺序不对就会加载错库,导致 ns 启动立刻 segfault。这是我在 CentOS 上吃过的大亏,当时系统自带 tcl8.5,结果 ns 一直段错误,用ldd $(which ns)查了半天才发现。

4. 验证安装并跑通第一个仿真实验:考验这套环境是骡子是马

4.1 快速验证 ns 和 nam 可执行文件

环境变量配置完后,在任意目录下输入以下命令做冒烟测试:

which ns ns -f /dev/null

第一条命令会输出 ns 可执行文件的绝对路径,比如/home/yourname/ns-allinone-2.26/bin/ns。这能确认 PATH 配置生效。第二条命令ns -f /dev/null是让 ns 解析一个空文件并静默退出,如果环境有问题,这一步就会暴露动态库加载错误或 tcl 解释器初始化失败。正常情况下这条命令在几百毫秒内没有任何输出就退出,说明基本跑通。如果报了error while loading shared libraries: libotcl.so,那说明LD_LIBRARY_PATH设错或者没 source。

nam 的验证有点不同,我一般不直接执行 nam 命令(因为它是图形界面,在没有 X 的服务器上会报错),而是放在下一个示例里,让它随仿真结果一起启动。

4.2 写一个最小 Tcl 脚本跑通无线场景

真正能验证环境完整的,是在示例目录里跑通自带脚本。NS-2 自带了一堆tcl/ex和tcl/test目录下的现成测试脚本,我建议先用它们来验货。比如跑一个最简单的有线网络场景:

cd ~/ns-allinone-2.26/ns-2.26/tcl/ex ns simple.tcl

simple.tcl是 NS-2 自带的一对节点间 TCP 传输的例子。命令执行后终端会刷出一堆 trace 信息,包括每个时间点的+,-,r,d事件记录,最后生成out.tr这个 trace 文件。如果你能顺利看到这些输出,说明你的 ns-2.26 主程序完全正常。同时还会生成一个nam动画文件,一般叫out.nam,用nam out.nam就能打开动画窗口回放整个传输过程。

我建议输出文件都重定向一下,别看 trace 刷屏:

cd ~/ns-allinone-2.26/ns-2.26/tcl/ex ns simple.tcl > /dev/null 2>&1 ls -l out.tr head -5 out.tr

参数说明:> /dev/null是把正常输出丢弃,2>&1是把错误输出也一起丢弃,目的是让终端干净。head -5则是看 trace 文件前五行格式,标准格式是事件 时间 节点 层 标志 序号 类型 包大小 源IP 目的IP 序号。如果 head 出来的信息符合这个布局,说明 trace 生成正确,NS-2.26 的整个工具链已经通了。

4.3 无线移动场景的验证与 nam 动画回放

如果你要跑的是无线自组网方向,NS-2.26 最常见的用法是跑一个带setdest(节点移动轨迹生成工具)的 AODV 场景。我写了一个最小可跑的脚本给你参考:

cd ~/ns-allinone-2.26/ns-2.26 cat > wireless_test.tcl << 'EOF' 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(nn) 10 set val(stop) 50 set ns_ [new Simulator] set tracefd [open wireless.tr w] $ns_ trace-all $tracefd set namtrace [open wireless.nam w] $ns_ namtrace-all-wireless $namtrace $val(x) $val(y) set topo [new Topography] $topo load_flatgrid $val(x) $val(y) create-god $val(nn) $ns_ node-config -adhocRouting AODV \ -llType $val(ll) \ -macType $val(mac) \ -ifqType $val(ifq) \ -ifqLen 50 \ -antType $val(ant) \ -propType $val(prop) \ -phyType $val(netif) \ -channelType $val(chan) \ -topoInstance $topo for {set i 0} {$i < $val(nn)} {incr i} { set node_($i) [$ns_ node] $node_($i) set X_ [expr $i * 50.0] $node_($i) set Y_ 250.0 $node_($i) set Z_ 0.0 } $ns_ at 1.0 "puts \"start\"; set udp [new Agent/UDP]; set sink [new Agent/Null]; $ns_ attach-agent \$node_(0) \$udp; $ns_ attach-agent \$node_(9) \$sink; $ns_ connect \$udp \$sink; set cbr [new Application/Traffic/CBR]; \$cbr set packetSize_ 512; \$cbr set rate_ 1Mb; \$cbr attach-agent \$udp; \$cbr start; \$udp start" $ns_ at $val(stop) "stop" $ns_ at $val(stop).0001 "puts \"NS EXITING...\"; $ns_ halt" $ns_ run EOF /usr/bin/ns wireless_test.tcl

这段脚本定义了一个 500*500 米平面上的 10 个无线节点,节点 0 向节点 9 发送 CBR 流,路由协议用 AODV。node-config是 NS-2.26 里面向对象节点配置的中心接口,-adhocRouting AODV指定路由协议,-ifqLen 50设接口队列长度,-phyType指定物理层模型。这段代码是无线仿真的典型骨架,你在论文里看到的吞吐量图、端到端延迟图都是在这个基础上加统计代码得来的。

跑完后用nam wireless.nam就能回放动画。如果动画窗口能正常弹出来且节点移动逻辑可见,那恭喜你,ns-allinone-2.26这套东西已经具备实际干活的能力了。nam 启动慢或者黑屏的问题,我放在第五章排障细讲。

5. 避坑指南:ns-allinone-2.26 在 Linux 上的 5 个经典踩坑记录

5.1 编译时报错g++: internal compiler error: Killed

现象:./install执行到ns-2.26主程序编译时,终端提示g++: internal compiler error: Killed,然后 make 进程退出。

原因:这通常不是代码错误,而是虚拟机或小内存机器在编译 C++ 大文件时被杀掉了,最常见是编译tcl8.4.5或otcl达到了内存上限。Ubuntu 桌面版默认没有 swap 或者 swap 太小,编译链接时内存不够就触发 OOM killer。

解决:先看可用内存free -h,不足 2GB 就加 swap 或用make -j1强制单线程编译。我当时的处理是把虚拟机内存调到 4GB,同时在install脚本里的 make 命令后加-j1,降低并行度。另外也是用apt install build-essential把g++版本换掉,升级到兼容版本。

5.2 nam 启动后窗口黑屏或闪退

现象:nam wireless.nam能启动进程,但窗口是黑屏,或者过几秒自动崩溃退到终端,没有任何报错。

原因:这是典型的 X11 渲染兼容性问题。NS-2 的 nam 基于 Tk 绘图,默认走 X11 共享内存扩展 MIT-SHM。在新版 Xorg 里,MIT-SHM 的访问控制变了,特别是用 Xvfb 或者远程 X forwarding 时,XShmGetImage会失败导致黑屏或崩溃。

解决:不让它走共享内存,改为 XPutImage。在启动 nam 前设置:

export QT_X11_NO_MITSHM=1 nam wireless.nam

当然有些发行版还要求export LIBGL_ALWAYS_SOFTWARE=1,强制软件渲染,避免 GPU 驱动和旧版 Tk 冲突。我自己的环境里第一条就解决了,但同事的 N 卡驱动环境下必须两条一起设才行。

5.3ns命令报couldn't load file "libtcl8.4.so"或直接段错误

现象:ns simple.tcl时终端直接提示Segmentation fault (core dumped),或者ns -f /dev/null报缺少动态库。

原因:动态库路径配置不对。ns 二进制内部用相对路径或绝对路径找libtcl8.4.so、libotcl.so。如果你用sudo执行 ns,sudo 会清掉用户的LD_LIBRARY_PATH,导致系统去/usr/lib里找,而那里没有 8.4 版本。

解决:不用 sudo 执行 ns,或者把LD_LIBRARY_PATH写入/etc/environment。我用的是第二个方案,因为后面要跑大规模仿真,脚本里可能调用sudo tcpdump之类的辅助工具,环境变量全局共享省心。注意写/etc/environment后要注销重新登录才生效。

5.4 Tcl 脚本里写Agent/Null报unknown option "sink"

现象:照着网上教程写无线仿真,定义了new Agent/Null之后,attach-agent 时提示unknown option或类不存在。

原因:NS-2.26 的类全名和你记的不一样。Agent/Null是老写法,但 NS-2.26 里类分层更细,常见是Agent/Null依然有效,更多情况是脚本里把Agent/UDP和Agent/Null写混了,或者sink变量名跟系统内置关键字冲突。

解决:把 sink 实例改名为sink_或null_sink,同时确认脚本里没有丢掉set sink [new Agent/Null]这一行。这个错误属于手滑类,群里十个人有八个是少写一行。我在 5.2 节里的无线示例脚本中就用$sink这个变量名,你可以直接抄。

5.5 跑仿真时 trace 文件里全是mac-layer丢包但抓不到原因

现象:无线场景中的 UDP 流,端到端吞吐几乎为零,落到 trace 文件看,全是MAC层丢包标记,但无线信道参数看起来没问题,物理层配置也对。

原因:这是典型的TwoRayGround传播模型下节点距离太大或发射功率不够的通信范围问题。NS-2.26 默认 802.11 发射功率换算后的通信半径只有 250 米左右,如果你把 10 个节点散布在 1000*1000 的平面上,大多数节点彼此不在传输半径内,包自然发不出去。

解决:把传播模型换成Propagation/Shadowing并用较小的路径损耗指数,或者用Phy/WirelessPhy里的Pt_(发射功率)调大。我一般直接把节点部署范围缩小到 200*200 或者把第一段代码里的val(prop)改成Propagation/Shadowing,并设置pathlossExp_ 1.8,这样就能在保持拓扑不变的前提下让包传起来。

6. 把 trace 文件变成论文图表:awk 与 gnuplot 的配合技巧

如果仿真已经能顺利生成wireless.tr,下一步就是把 trace 里的丢包率、吞吐量整理成图表。NS-2.26 自带的 xgraph 有点老,我基本只用它做快速预览,整图还是用 gnuplot。先看一个 awk 命令,统计无线场景 CBR 流的吞吐量:

awk '/^r/ && $4 == "AGT" && $7 == "cbr" { sum += $6; if ($2 > 1.0) { total += sum; sum = 0; } } END { printf("Average Throughput: %.2f kbps\n", total / 49 * 8 / 1000); }' wireless.tr

这段 awk 逐行读 trace 文件,$4 == "AGT"表示只在应用层接收记录里统计,$7 == "cbr"限定了流量类型。$6是包大小(单位是字节),累加后把字节数乘 8 转成比特,再除以仿真总时长 49 秒得到平均吞吐。这里有个细节:CBR 流是第 1 秒启动,第 50 秒停止,所以算平均时扣掉了第一秒前的空闲时间。如果你要的是瞬时吞吐曲线,那 awk 里就要每隔 0.5 秒打一个点。

拿到吞吐量统计后,用 gnuplot 画出端到端延迟分布,常用命令如下:

gnuplot << EOF set terminal png size 800,600 set output "delay.png" set xlabel "Time (s)" set ylabel "End-to-End Delay (ms)" plot "delay.dat" with lines title "AODV delay" EOF

set terminal png输出图像文件,可以插入论文;with lines让数据点连成光滑线,比散点图更适合看趋势。如果你没有delay.dat,需要在 Tcl 脚本里对每个接收事件都用expr $now - $send_time求出延迟再写入文件,这一般要配合 agent 的回调对象来做,属于进阶写法。我自己的做法是直接在 awk 里对+和r事件做配对计算延迟,然后用print重定向成delay.dat。

最后给你一个我自己的习惯:每次开启新实验前先跑一遍simple.tcl做环境自检,再跑真实场景,能省掉大量查环境变量的时间。碰到奇怪的挂起和段错误,优先检查LD_LIBRARY_PATH,而不是怀疑脚本逻辑。这套ns-allinone-2.26虽然老,但在教学和特定论文复现里依然能打,只要把坑填平,它可以稳定跑出可复现的数据。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询