ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ns-allinone-2.26在Ubuntu 22.04的完整安装指南与排坑

ns-allinone-2.26在Ubuntu 22.04的完整安装指南与排坑

简介:NS-2网络仿真平台的一体化安装包ns-allinone-2.26,内置ns-2.26主程序及Tcl/Tk、OTcl等依赖组件,面向网络协议学习、课程实验与科研仿真用户,支持MAC层、路由层及无线/有线网络的行为建模,无需实际硬件即可验证组网机制。压缩包约50.44MB,共含5056个文件,类型覆盖C/C++源码、Tcl/OTcl脚本、HTML/Tex文档、测试用例和仿真场景数据,解压后即可搭建本地实验环境。已有108人浏览学习。用户可借助该资源创建多节点拓扑,配置不同路由协议、队列管理与流量模型,配合nam可视化工具观察分组转发过程,统计时延、丢包率、吞吐量等关键指标;也可通过研读源码和示例脚本,学习协议实现细节与仿真扩展方法,为课程设计、毕业设计及网络性能对比研究提供完整可靠的实验基础。

1. ns-allinone-2.26 还没过时:为什么 2024 年还在装 2004 年的模拟器

看到ns-allinone-2.26.tar.gz这个文件名,第一反应多半是“这是古董吧”。确实,ns-allinone-2.26 是 2004 年前后发布的网络仿真器打包版本,里面包含了 ns-2.26 核心、nam 动画回放工具、xgraph 绘图工具以及配套的 Tcl/Tk 运行库。二十年后它依然是国内高校《计算机网络》实验课和路由算法、拥塞控制、MAC 协议研究中的常客,原因很朴素:它足够小,依赖足够老,行为足够能被“看穿”,而且 allinone 模式把整套工具链打包成一个压缩包,让使用者不必去逐一手工匹配 Tcl 和 OTcl 的版本。

这篇文章会把ns-allinone-2.26.tar.gz从解压到跑通第一个仿真脚本的全过程,以及我在这条路上踩过的坑原原本本讲清楚。适合刚拿到导师给的实验要求、却不知道从哪下手的研究生,也适合想在容器或旧机器上复现 NS-2 实验的老手。目标只有一个:让ns命令在你机器上真正跑起来,并且输出你能看懂的结果。

2. 先拆开 allinone:ns-allinone-2.26 里到底装了哪些组件,为什么必须整包安装

2.1 组件依赖链:从 Tcl 到 NS 核心,每一层都不能乱

ns-allinone-2.26.tar.gz不是单个程序,而是一整条依赖链的集合。常见做法是先解压再看内容,官方维护者把这套依赖打包在一起,就是为了避免使用者自己到各处找版本匹配的源码。

解压后能看到这几个关键目录:tcl8.4.5、tk8.4.5、otcl-1.0a7、tclcl-1.13、ns-2.26、nam-1.11、xgraph-12.2。它们之间的关系是这样的:NS-2 本身是 C++ 写的事件驱动模拟器,但它的场景描述语言是 OTcl(面向对象的 Tcl 扩展),所以用户写的.tcl脚本会先被 OTcl 解释器解析,再通过 TclCL 这个胶水层把 C++ 对象暴露给 Tcl 层调用。没有 tclcl,C++ 类和 Tcl 解释器之间就接不上。nam 和 xgraph 则是在仿真结束后,读取生成的 trace 文件做动画回放和曲线绘制。

所以这包东西的正确安装顺序是:先装 Tcl/Tk(底层解释器和图形库),再编 OTcl(Tcl 的面向对象扩展),接着编 tclcl(Tcl/C++ 接口层),最后才轮到 ns-2.26 本体和 nam、xgraph 两个辅助工具。如果跳过 tclcl 直接编 ns,configure 阶段就会报找不到otcl.h或tclcl.h的错误。用命令行检查归档内容也能验证这一点,文件列表顺序基本就是编译依赖顺序。

tar -tzf ns-allinone-2.26.tar.gz | head -50

-t表示列出文件清单而不解压,-z指定通过 gzip 解压读取,-f后跟文件名。看到输出里第一个目录是tcl8.4.5,基本就能确定 allinone 包的组件秩序。我通常还会用tar -tzf重定向到文件里,方便对照每一层目录。

2.2 为什么 2.26 是教学和科研里的“甜点版本”

NS-2 的后续版本还有 2.28、2.29、2.30、2.31、2.34、2.35,为什么 2.26 至今还在被大量课程引用?一个现实原因:大量课件、参考书和学位论文里的实验脚本是用 2.26 时代的 API 写的。比如Agent/TCP的默认参数、LossMonitor的用法、trace 文件格式,2.26 到 2.31 之间虽然有调整,但差异不大,而网上能找到的解析笔记大部分基于 2.26/2.34 版本。

另一个原因是“甜点版本”的硬件要求低。整个 allinone 编译完后占地不到 300M,运行时内存占用基本在几十兆级别,相比 NS-3 那套需要 python 绑定和 waf 构建的体系,NS-2.26 在任何一台虚拟机甚至树莓派上都能跑。这反过来也成为它的一个坑:新系统的 GCC 默认版本太高,直接编译老源码会翻车。这个坑后面单独说。

2.3 同时装 ns-3 或者多版本 NS-2?我的选型建议

不少读者会纠结要不要同时保留 NS-2.26 和 NS-3.x。我的建议是:如果课程或论文只需要 2.26,就别引 NS-3 进来找麻烦。两个体系的 Tcl 脚本完全不通用,安装位置和环境变量也会互相干扰。

如果确实需要多版本共存,常见做法是每次只切换TCL_LIBRARY和PATH环境变量,把不同版本装到/opt/ns-allinone-2.26和/opt/ns-allinone-2.35这种独立目录下。不要试图用同一个安装目录覆盖安装,两个版本的lib目录里都有各自的otcl和tclcl动态库,覆盖后经常出现“configure 通过但运行时加载不了库”的诡异问题。我一般会在~/.bashrc里写两个 shell 函数来切换,而不是把所有路径一股脑写死在环境变量里。

3. 从零到能跑:Ubuntu 22.04 上安装 ns-allinone-2.26 的完整命令链

3.1 安装前环境检查:先把编译工具链降到一个能用的组合

在 Ubuntu 22.04 上第一次装 ns-allinone-2.26,最大的翻车点就是系统自带 GCC 11。NS-2.26 的源码是 2004 年前后的 C++ 写法,GCC 4.8/5.5 可以顺利编译,GCC 11 会报出一堆字符串常量、register关键字、隐式类型转换之类的错误。但完全卸载新 GCC 不值得,我常用做法是装一个老版本编译器,然后通过别名或软链接让构建脚本去调用它。

sudo apt update sudo apt install -y gcc-4.8 g++-4.8 ls /usr/bin/gcc* /usr/bin/g++*

上面的输出里如果能看到gcc-4.8、g++-4.8,说明降级工具链已经就位。Ubuntu 22.04 官方源里可能没有 gcc-4.8,这种情况下可以从 Ubuntu 18.04 的源或第三方 PPA 安装,也可以用apt install gcc-5 g++-5替代,后面所有命令里的4.8改成5即可。

3.2 解压并逐层编译:每一步都看关键输出

先建立安装目录。我习惯把 allinone 放到/opt下,原因是权限问题比较直接,普通用户只读,编译时用 sudo,避免在~下出错后和用户配置混在一起。

sudo mkdir -p /opt/ns2 sudo cp ns-allinone-2.26.tar.gz /opt/ns2/ cd /opt/ns2 sudo tar -xzf ns-allinone-2.26.tar.gz cd ns-allinone-2.26

这里有个细节:解压后ls看得到install脚本,它是一个顺序编译脚本,会逐个进子目录./configure && make && make install。如果直接sudo ./install,大概率会失败。更稳妥的方式是手动按依赖顺序编译。原因是 install 脚本默认调用系统 gcc,它不会替你切换老版本编译器。

手动编译时,先进入 tcl 目录:

cd tcl8.4.5 sudo ./configure --prefix=/opt/ns2/ns-allinone-2.26 sudo make clean sudo make CFLAGS="-O2 -fcommon" -j4 sudo make install

--prefix指定安装路径,这里让所有子组件都装进 allinone 自己的目录,而不是散落到/usr/local,后面环境变量配置会非常集中。CFLAGS里的-fcommon是为了绕过 GCC 10 以后对多重定义的默认报错,2.26 时代不少源文件依赖这个老行为。-j4是并行编译。

接着是 tk,它依赖 tcl,所以要确保刚才的 tcl 已经make install成功:

cd ../tk8.4.5 sudo ./configure --prefix=/opt/ns2/ns-allinone-2.26 sudo make clean sudo make CFLAGS="-O2 -fcommon" -j4 sudo make install

tcl 和 tk 是 Tcl/Tk 的解释器库与 GUI 库。这一步里如果 configure 报错,多半是找不到 tcl 的头文件,需要把--with-tcl参数加上,指向/opt/ns2/ns-allinone-2.26/lib。

然后编译 otcl:

cd ../otcl-1.0a7 sudo ./configure --with-tcl=/opt/ns2/ns-allinone-2.26/tcl8.4.5 \ --with-tk=/opt/ns2/ns-allinone-2.26/tk8.4.5 \ --prefix=/opt/ns2/ns-allinone-2.26 sudo make clean sudo make -j4 sudo make install

otcl-1.0a7是 Tcl 的面向对象扩展库,NS-2 的节点、链路、代理对象都靠它在 Tcl 层创建。configure 时要显式告诉它 tcl 与 tk 的位置,否则它可能去找系统路径里新版 Tcl,导致后续版本不匹配,运行时报version conflict或者can't find package otcl。

接着是 tclcl:

cd ../tclcl-1.13 sudo ./configure --prefix=/opt/ns2/ns-allinone-2.26 sudo make clean sudo make -j4 sudo make install

tclcl 这层没有任何交互界面,纯接口层,容易编过。我通常在make完成后 ls 一下lib目录里是否出现了libtclcl.so或libtclcl.a。没有这个文件就继续往下,后面 ns configure 一定会失败。

最后编译 ns-2.26 本体:

cd ../ns-2.26 sudo ./configure --prefix=/opt/ns2/ns-allinone-2.26 sudo make clean sudo make -j4 CFLAGS="-O2 -fcommon -Wno-register -Wno-deprecated"

这一步耗时最长,大概五到二十分钟,取决于机器性能。看到生成ns这个可执行文件且没有致命错误,编译阶段就算过了。

3.3 环境变量配置:让ns命令在任何目录都能用

编译完成后,ns命令还不能直接用。因为它运行时需要加载 tcl 库、otcl 库和 nam 的共享库,必须把动态链接库路径告诉系统。

export PATH=$PATH:/opt/ns2/ns-allinone-2.26/bin:/opt/ns2/ns-allinone-2.26/tcl8.4.5/unix:/opt/ns2/ns-allinone-2.26/tk8.4.5/unix export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/ns2/ns-allinone-2.26/lib export TCL_LIBRARY=/opt/ns2/ns-allinone-2.26/tcl8.4.5/library

LD_LIBRARY_PATH是最关键的一项。NS-2 在运行时动态加载libotcl.so、libtclcl.so这些库,如果没设这个变量,运行.tcl脚本时会出现error while loading shared libraries: libtclcl.so之类的报错。TCL_LIBRARY则告诉 Tcl 解释器标准脚本库在哪里,这个路径一旦指向系统自带的 Tcl 版本(比如 8.6),会和源码编译的 8.4.5 产生混淆,常见的现象是can't find package tcl或者Tcl_Init error。

把这三行追加到~/.bashrc后,source ~/.bashrc,然后执行:

which ns ns --version

输出ns version 2.26便说明命令已生效。很多人在这一步卡住,不是编译失败,而是新开的终端没有 source 一次,于是ns找不到。

4. 安装期翻车清单:GCC、X11、TCL_LIBRARY 这些坑我都替你踩过

4.1 现象:Makefile 里出现大段invalid conversion from const char* to char*

原因:GCC 11 对 C++ 字符串字面量的隐式转换收紧了。NS-2.26 源码里大量用char* p = "static string"这种写法,新版编译器直接报 error。

解决:最省事的方法是装 gcc-4.8/g++-4.8 后在编译命令里加软链接。但如果你不想动系统编译器,另一个可靠方案是为 configure 阶段和 make 阶段分别指定 CC/CXX 变量,让老源码用老编译器编译:

./configure CC=gcc-4.8 CXX=g++-4.8 --prefix=/opt/ns2/ns-allinone-2.26 make CXX=g++-4.8 CC=gcc-4.8 -j4

4.2 现象:运行 nam 或 xgraph 时提示X11/Xlib.h: No such file or directory

原因:这两者是图形工具,configure 需要 X11 开发库。最小系统或容器镜像默认不装图形开发头文件。

解决:装齐再重新 configure:

sudo apt install -y libx11-dev libxmu-dev libxext-dev libxt-dev

装完后回到 nam-1.11 和 xgraph-12.2 目录重新./configure && make。如果还有 openGL 相关报错,再加libgl1-mesa-dev也一样搞定。

4.3 现象:ns能启动,但执行脚本时报Error: can't find package Tcl

原因:TCL_LIBRARY或TCLLIBPATH指向了系统自带的 Tcl 8.6 库目录,而 NS-2.26 需要的是编译出来的 Tcl 8.4.5 库。

解决:确认~/.bashrc里路径不包含/usr/lib/tcl8.6这类目录。最彻底的做法是只保留 allinone 目录的 path:

unset TCL_LIBRARY export TCL_LIBRARY=/opt/ns2/ns-allinone-2.26/tcl8.4.5/library

4.4 现象:nam窗口弹出来一片黑,或者干脆一闪而过

原因:这通常不是软件本身的问题,而是没有正确加载 trace 文件,或显示器驱动对老式 OpenGL 调用支持不好。

解决:先确认在 NS-2.26 安装目录下运行nam而不是直接./nam带自定义脚本,然后用示例自带 trace 文件做回放测试。如果需要回放自己的 trace,确保simulator run结束后 trace 文件有完整写入,set ns [new Simulator]里定义的 trace 文件名要和 nam 打开的文件名一致。GUI 黑屏时,可以尝试加参数:

nam -t tracefile.nam

-t参数含义是加载指定 trace 文件后暂停,等用户按键再开始回放,方便定位数据问题。大部分黑屏其实是 trace 文件里节点坐标没有初始化。

4.5 现象:安装目录权限正常,但普通用户运行ns时总是 Segmentation Fault

原因:常见于/opt安装时用 sudo 编译,而共享库文件的权限或属主不对导致加载失败,或者新内核的地址空间随机化让老版 OTcl 库崩溃。

解决:先检查库文件权限:

ls -l /opt/ns2/ns-allinone-2.26/lib/

如果属主不是当前用户,用sudo chown -R $USER /opt/ns2改归属。老版本 OTcl 在部分新内核上有概率段错误,可以把内核参数设为兼容模式试一下,但不建议为此冒险。稳妥做法是容器内或虚拟机里跑,kernel 版本一般不会过于激进。

5. 跑通第一个仿真:从编写 Tcl 场景到解析 trace 结果

5.1 最小 TCP 场景:ns命令的完整执行流程

安装完成后最合适的开机测试是写一个最简单的自适应场景。先创建文件first.tcl。

set ns [new Simulator] set trace_fd [open first.tr w] $ns trace-all $trace_fd set n0 [$ns node] set n1 [$ns node] $ns duplex-link $n0 $n1 5Mb 2ms DropTail set tcp [new Agent/TCP] set sink [new Agent/TCPSink] $ns attach-agent $n0 $tcp $ns attach-agent $n1 $sink $ns connect $tcp $sink set ftp [new Application/FTP] $ftp attach-agent $tcp $ns at 1.0 "$ftp start" $ns at 2.0 "finish" proc finish {} { global ns trace_fd $ns flush-trace close $trace_fd puts "Simulation finished" exit 0 } $ns run

这段脚本干了四件事:创建仿真器对象并打开 trace 文件,建立两个节点并用一条 5Mb 带宽、2ms 延迟的链路连接,挂载 TCP 代理和 FTP 应用层流量,再调度 finish 过程在 2 秒时结束仿真。第五行的trace-all表示全量记录,事件丰富但文件膨胀快,小场景没问题。第十六行的puts输出在终端里能直接看到Simulation finished,没有异常就说明 NS 命令链已经正常工作。

执行方式:

cd /opt/ns2/ns-allinone-2.26/ns-2.26 ns first.tcl

5.2 用 awk 从 trace 文件提取吞吐量:交付第一个观察结论

仿真结束后first.tr文件里记录了所有事件。NS-2.26 的 trace 格式为事件类型、时间、源节点、目的节点、包类型、包大小、标志、流 ID 等字段。写个 awk 命令统计从 1 秒到 2 秒之间 TCP sink 收到的总字节数,计算吞吐量:

awk '{if ($1 == "r" && $5 == "tcp") {recv_bytes += $6; end = $2}} END { elapsed = end - 1.0; printf("Received %d bytes in %.2f seconds, throughput = %.3f Mbps\n", recv_bytes, elapsed, (recv_bytes * 8.0) / (elapsed * 1000000)); }' first.tr

第六字段$6是包大小(字节),第一字段$1的r表示 receive 事件。链路带宽 5Mb,延迟 2ms,理论上 TCP 吞吐受窗口和 RTT 限制,不会跑满 5Mb,所以结果如果是一个几百 Kbps 到 1Mbps 之间的数字,属于正常范围。如果你的结果是 0,大概率是$ftp start之前没有$ns at 1.0,或者 sink 没有正确连接到节点。

5.3 nam 可视化回放:确认行为是否符合直觉

很多新手写完脚本只看终端输出还不放心,想亲眼看到数据包在链路上流动。用 nam 回放 trace 文件的命令如下:

nam first.nam

需要先在 first.tcl 里增加一行:

set nam_fd [open first.nam w] $ns namtrace-all $nam_fd

注意namtrace-all和trace-all是两套独立记录器,first.nam记录拓扑结构和包移动动画,first.tr记录详细事件。生成后用nam first.nam就能看到两个圆点节点和一条链路,FTP 启动后会看到灰色方块从 n0 流向 n1。看不到动画或者一打开就退出,按 4.4 的排查方式处理一下。

6. 让仿真结果可复现:固定随机种子、批量实验与回归验证

最后一个要讲的是让实验可复现,而不是跑一次出一堆数字后无法解释。NS-2.26 的随机数模块在不同版本间行为差异很大,同一份脚本在不同机器上跑结果不完全一致。常见做法是在脚本开头固定随机数种子。

set rng [new RNG] $rng seed 12345

再配合ns-random和RandomVariable类使用。对于需要统计多次运行结果的实验,我习惯写一个 bash 循环批量执行,然后汇总 trace 结果到一个 CSV 文件。这样跑完一次实验,拿到的是可对照的表格而不是一个孤立的数字。

验证安装成功与否也有一个标准动作:进入ns-2.26/tcl/ex目录,跑一遍别人验证过的示例脚本。这些脚本在发布时就能通过,如果你跑出来报错,那就是安装本身有问题;跑通了,说明整个 allinone 包在你的机器上没问题。我每次装完都会做这个 sanity check,再跑自己的脚本。

另外建议在~/.bashrc里把环境变量封装成一个函数。比如叫ns2env,只在需要时启用,而不是每次开终端都往 PATH 里塞老路径,避免新项目用到现代工具链时互相干扰。整个系统里同时存在多个版本的仿真器时,这种隔离方式能救你一命。这算是我这些年装仿真工具攒下的最实在的一条习惯,希望帮到你。

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

返回列表