简介这是一份面向NS2入门者与网络仿真研究者的代码包聚焦网络协议仿真、路由算法、移动模型与性能统计等核心场景。通过28个文件、623KB的紧凑组织读者可直接运行Tcl脚本观察TCP拥塞控制、DSDV路由决策和Random Waypoint移动节点的行为并借助nam动画、tr轨迹与awk统计脚本完成仿真结果分析资源包含8个Tcl配置脚本、2个C源码及头文件、nam/tr结果文件以及gnuplot绘图脚本覆盖从基础网络拓扑搭建到OOPSI协议扩展的完整链条。已有222人学习下载内容按章节与实验组织从第二章基础示例到第六章xgraph绘图再到第七章mflood源码剖析配合示例逐步演示数据包发送、路由转发、移动场景建模与性能指标提取。学习者既能理解NS2的事件驱动机制也能通过修改参数和脚本自主开展协议对比与网络性能实验。1. ns2.rar 里的 NS2 代码过时仿真器的最后一块价值洼地ns2.rar 这个包名在压缩包分享时代被研究生们传来传去里面装的几乎都是 NS2 相关代码tcl 仿真脚本、nam 动画文件、trace 结果运气好的还会附带 C 扩展源码。NS2 的正式版停在 2.35 不再更新但网络仿真论文里的对比实验至今大量引用这套代码。我为什么还推荐去解压这种老包因为论文里讲不清楚的算法细节往往只能从可运行的示例代码里倒推而 NS3 的 API 演进报错太多和旧论文结果对齐非常难。NS2 代码简单、依赖少适合做路由协议和无线网络的基础验证也适合作为理解离散事件仿真的入门标本。接下来我会按平时带师弟的顺序走一遍先拆开压缩包看文件布局再用最小 tcl 脚本跑通链路然后从 trace 提取论文指标最后改 C 源码做自定义协议。新手能跟上熟手可以跳过前四章直接看避坑和改码。2. 拆开 ns2.rar搞明白 NS2 代码的四种文件与两层架构2.1 解压后最常见的四类文件tcl、nam、tr、C从网上或者老师 U 盘拿到的 ns2.rar解压后通常不是一整个 ns-allinone 安装目录而是一个实验文件夹。里面最常见的是四类文件我先花两分钟把这四类东西的职责说清楚因为后面对代码的操作都会落在它们身上。第一类是 tcl 脚本也就是扩展名为 .tcl 的仿真入口文件。NS2 里所谓“跑代码”绝大多数时候就是执行一条 ns xxx.tcl 命令。tcl 脚本负责创建节点、建立链路、挂载协议栈、调度事件最终把运行过程写进 trace 文件。第二类是 nam 文件扩展名为 .nam它是 nam 可视化工具读取的动画记录包含节点的位置、链路状态和分组流动轨迹。答辩的时候打开 nam 演示比念数据直观得多。第三类是 tr 文件也就是 trace 日志。ns 运行时把每个分组事件的细节按行追加到这个文本文件里吞吐量、丢包率、端到端延迟都是从它里边算出来的这是论文数据真正的来源。第四类是可选的 C 源码包括 .cc 和 .h 文件当你需要修改协议核心逻辑、增加新的 Agent 类时才会用到它们。我不建议一上来就把 tcl 文件拖进文本编辑器乱改。先把所有文件放进同一个纯英文路径比如 D:\ns2lab 或者 ~/ns2lab目录名不要有中文和空格。NS2 是老代码对路径里的特殊字符处理很差中文路径经常导致 nam 和 trace 输出异常这是第一个不需要调试就能避开的坑。2.2 OTcl 与 C 两层架构为什么改 NS2 代码要分清编译层和解释层NS2 代码看起来只有 tcl 脚本但它的底层是 C 和 OTcl 两套体系缝合出来的。理解不了这一层后面改协议时会彻底抓瞎因为你会发现“改了一个参数没反应”或者“加了新 Agent 却无法实例化”。C 层负责时间关键的部分比如分组格式、队列管理、路由查找、调度器事件循环。这些代码在 ns 启动之前就已经编译成二进制了运行效率高但不能在脚本里动态改动。OTcl 层负责配置和组装脚本里写的 set ns [new Simulator]、$ns duplex-link 这类语句都由 OTcl 解释器执行它把 C 对象包装成 tcl 对象让你能像搭积木一样组织仿真场景。常见的做法是C 写协议行为OTcl 写场景配置。一个对象要被脚本使用必须经过 TclClass 注册比如 C 里的类经过注册后才能在 tcl 里写成 Agent/UDP。你从 ns2.rar 里看到的 tcl 脚本只是冰山一角真正的协议行为在对应目录的 C 文件里。这就解释了为什么改 NS2 代码有两种完全不同的路线。只调链路带宽、流量速率、节点数量属于配置层改动不重新编译要改路由协议字段、增加新的控制报文、改变邻居发现逻辑属于核心层改动必须动 C 源码然后 make。分清这条界线可以省掉一大半白费的力气。2.3 环境准备把 ns 命令装进 PATH并验证它真的可用从 ns2.rar 里拿到的散件通常只是实验用脚本真正执行它们还需要一套能运行的 NS2 环境。ns-allinone-2.35 是最常见的安装包解压完会有 ns-2.35、nam、xgraph、tcl8. x 等子目录。装好之后最重要的事是设置环境变量让系统知道 ns 命令去哪找。我一般会在 ~/.bashrc 里追加下面的内容路径按实际解压目录修改export NS_HOME$HOME/ns-allinone-2.35 export PATH$NS_HOME/bin:$NS_HOME/tcl8.5/unix:$NS_HOME/tk8.5/unix:$PATH export LD_LIBRARY_PATH$NS_HOME/tcl8.5/unix:$NS_HOME/tk8.5/unix:$NS_HOME/otcl-1.14:$NS_HOME/lib:$LD_LIBRARY_PATH逻辑说明NS_HOME 指向安装根目录后续所有路径都以它为基准避免在多个目录间来回切换时打错绝对路径。PATH 里加的是 bin、tcl 和 tk 的 unix 子目录这样 ns、nam、xgraph 这些命令才能被直接调用。LD_LIBRARY_PATH 是 Linux 下最容易被忽略的一项NS2 依赖 otcl 和 tk 的动态库不加它运行时经常报找不到 libtcl8.5.so 或者 libotcl.so。参数说明你机器上解压出来的 tcl 版本号不一定正好是 8.5先 ls 看一下把版本号替换进去tcsh 用户改成 setenv 写法原理相同。修改完执行 source ~/.bashrc 让配置生效然后运行命令验证。which ns ls -l $NS_HOME/bin/ns如果 which ns 输出了完整路径说明 PATH 生效如果提示 command not found再检查 bashrc 里有没有语法错误、路径目录名是不是写错。validate ns 能正常启动执行 ns会进入一个交互式 tcl shell看到 %. 提示符就说明基本可用。Windows 上不建议直接双击 ns.exe。NS2 的 Windows 移植版依赖模拟环境直接在 cmd 里跑 ns 极易报缺失动态库。我这边带过的新人最后都用 WSL 或虚拟机里的 Linux 完成全部仿真稳定性好很多。3. 用最小 NS2 代码跑通链路仿真从 tcl 脚本到 out.tr3.1 最小可运行的 tcl 仿真骨架回到 ns2.rar 里的那一堆脚本不管它多复杂核心骨架都是同一套创建 Simulator、定义 trace 输出、创建节点和链路、挂载流量、调度开始和结束时间。下面这段是我用来验证环境是否正常的最小示例代码可以直接保存为 ns2_minimal.tcl 运行。# ns2_minimal.tcl # 最小网络仿真两个节点一条链路一个CBR流量源 set ns [new Simulator] set trace_fd [open out.tr w] $ns trace-all $trace_fd set nam_fd [open out.nam w] $ns namtrace-all $nam_fd proc finish {} { global ns trace_fd nam_fd $ns flush-trace close $trace_fd close $nam_fd exec nam out.nam } set n0 [$ns node] set n1 [$ns node] $ns duplex-link $n0 $n1 1Mb 10ms DropTail set udp0 [new Agent/UDP] set null1 [new Agent/Null] $ns attach-agent $n0 $udp0 $ns attach-agent $n1 $null1 $ns connect $udp0 $null1 set cbr0 [new Application/Traffic/CBR] $cbr0 set packetSize_ 500 $cbr0 set rate_ 800k $cbr0 attach-agent $udp0 $ns at 0.1 $cbr0 start $ns at 4.5 $cbr0 stop $ns at 5.0 finish $ns run逻辑说明前两行创建 Simulator 实例并打开 out.tr 和 out.nam 两个输出文件。finish 过程在所有事件完成后被调用负责冲刷缓冲区、关闭文件、启动 nam 可视化。接着创建两个节点用 duplex-link 建立双向链路带宽 1Mb、延迟 10ms、队列类型 DropTail。再挂载一个 UDP 发送代理和一个 Null 接收代理中间用 CBR 流量填充链路。最后的 $ns at 语句把三个时间点和对应动作绑定到调度器上。参数说明packetSize_ 是 CBR 包大小单位字节这里 500 字节接近实际网络中的小包。rate_ 是发送速率800k 表示 800kbps链路带宽是 1Mb这样的配比是为了让链路刚好处于不饱和到轻微拥塞之间跑出来的 trace 才看得出排队和丢包现象。如果你把 rate_ 改成 100k链路完全空闲丢包率会变成 0很多论文对比图就是这么“做”出来的但不建议。3.2 参数怎么调节点、链路、流量模型和定时器ns2.rar 包里的脚本不会老老实实只跑两个节点你看到的更多是几十个节点随机分布、多条 TCP 流并发的场景。要改这些首先得知道参数在哪个层级。节点数量由 $ns node 出现的次数决定通常配合循环语句创建。链路的核心参数有三个带宽、延迟和队列管理算法。DropTail 是简单丢弃尾部适合基础实验RED 和 SFQ 适合拥塞控制研究真实网络里的路由队列大多也不是简单的 DropTail论文对比时要注意说明。队列长度的设置在链路对象上默认值往往不够用批量传输大文件时容易提前丢包我会习惯显式设置 queue-limit。流量模型方面CBR 是恒定速率发送适合考察丢包和延迟上限TCP 流要配 FTP 或 Telnet 这类 Application 才会真正搬运数据。很多人从 ns2.rar 拿到的脚本里TCP 和 CBR 混在一起trace 文件事件非常密集awk 统计时必须区分包类型否则会把 TCP 的 ACK 包也算进 CBR 吞吐量里得出来的数字直接失真。定时器方面$ns at 后的第一项是时间第二项是字符串形式的命令。时间不一定非要用绝对时间用变量做偏移更稳妥比如 start_time 加 duration。我习惯把 CDN traffic 的开始时间放在 0.1s 而不是 0s给协议栈一点建立邻居表的时间无线场景尤其明显0 时刻发包经常撞上没有建立路由导致的丢包。3.3 运行与确认ns 命令执行后该检查哪些输出执行命令只需要一行但执行完不能只看有没有报错还要确认输出文件是否真的写入了数据。正确姿势是先运行cd ~/ns2lab ns ns2_minimal.tcl运行过程中终端通常没有输出但卡顿几秒后会自动调用 nam。如果终端静默退出应立刻检查 out.tr 是否生成、文件大小是否大于零、nam 窗口是否出现。正常的 trace 文件至少有几百行每一行的首字段是事件类型第二字段是发生时间。我验证脚本是否真正“跑起来”的标准不是看 nam 窗口能不能弹出来而是看 trace 文件里能不能同时找到入队、出队、接收、丢弃四类事件。如果只有入队和接收链路太空闲如果丢弃事件占到三成说明链路配置过载。这两种情况都不适合直接拿去做论文图先回头调整 rate 和 queue-limit 再继续。一个反直觉的槽点NS2 脚本里包名写错不会在运行时立刻崩溃。比如把 Agent/UDP 写成 Agent/UdpNS2 可能到创建对象那一步才报 invalid command name而整个文件前面几十行已经执行完了。所以改完脚本不要盯着终端等结果直接看 trace 文件首尾时间戳有没有覆盖完整仿真时长这比肉眼排查代码快得多。4. 从 NS2 trace 提取论文指标awk 统计吞吐量、丢包率与平均端到端延迟4.1 读懂 trace 文件一个数据包从入队到收到的完整轨迹NS2 的 trace 文件不是给人密密麻麻读的理解它的核心是搞清楚每一行的字段含义。以第 3 章的脚本为例out.tr 里典型一行长这样 1.0021 0 1 cbr 500 ------- 0 0.0 1.0 0 12 r 1.0105 1 0 cbr 500 ------- 0 1.0 0.0 3 8按空格切分后$1 是事件类型加号表示入队减号表示出队r 表示接收d 表示丢弃。$2 是时间戳单位秒。$3 是源节点 ID$4 是目的节点 ID$5 是包类型$6 是包大小字节数。$9 和 $10 是源地址和目的地址的“节点.端口”形式$12 是唯一包 ID。一个数据包的完整轨迹通常是这样上演的发送端应用产出数据后先在源节点队列入口出现一条加号记录调度器把包移出队列时出现减号记录包到达目的节点后出现一条 r 记录队列满导致容不下时出现 d 记录。注意 d 记录可能出现在入队阶段也可能出现在中间转发节点这取决于丢包发生在哪一跳。对新手来说做数据分析前先做一次“代码整理”非常关键。把每个实验的 tcl、tr、awk 脚本放进同一个目录文件名带上日期和参数比如 rtt10ms_rate800k.tr。不要把所有结果都堆进同名 out.tr跑第二轮实验就把上一轮数据覆盖了这种失误浪费的时间比写 awk 脚本多得多。4.2 一手 awk 统计脚本吞吐量、丢包率、平均端到端延迟awk 是处理 NS2 trace 最顺手的工具下面这段脚本可以直接保存为 stat.awk统计 CBR 流的三个核心指标。它按传统格式解析字段约定以 4.1 节为准实际使用前先拿 head 命令看一眼你的 trace 格式确认 $5 位置确实是 cbr。#!/usr/bin/awk -f # stat.awk: 统计CBR业务吞吐量、丢包率与平均端到端延迟 BEGIN { sent 0; recv 0; recv_bytes 0; delay_sum 0; delay_cnt 0; } { if ($5 cbr) { # 入队时记录包的发送时间用唯一包ID做key if ($1 ) { sent; send_time[$12] $2; } # 接收时累加字节数并计算端到端延迟 if ($1 r) { recv; recv_bytes $6; delay_sum $2 - send_time[$12]; delay_cnt; if (start 0) start $2; end $2; } } } END { if (sent 0) { drop_rate (sent - recv) / sent * 100; } else { drop_rate 0; } duration end - start; if (duration 0) duration 1e-9; printf 发送CBR包数: %d\n, sent; printf 接收CBR包数: %d\n, recv; printf 丢包率: %.2f%%\n, drop_rate; throughput recv_bytes * 8 / duration / 1e6; printf 吞吐量: %.3f Mbps\n, throughput; if (delay_cnt 0) { printf 平均端到端延迟: %.6f ms\n, delay_sum / delay_cnt * 1000; } else { printf 平均端到端延迟: 无接收包\n; } }逻辑说明第一部分在入队事件里记录发送时间以 $12 这个唯一包 ID 作为关联键第二部分在接收事件里累加字节数和延迟。END 块里计算丢包率分子是发送数减接收数分母是发送数吞吐量用接收字节数乘 8 换成比特再除以仿真持续时间延迟是接收时刻减发送时刻累加后取平均。参数说明整段代码只统计包类型为 cbr 的行这是刻意做的筛选避免 TCP ACK 和 UDP 的其他业务混进来。如果你的 trace 格式里包类型出现在别的字段先修改 $5 为对应字段号。delay_sum 的单位是 trace 里的秒最后乘 1000 转成毫秒输出论文里更常用毫秒。start 这个变量记录第一个接收包的时间end 是最后一个接收包的时间duration 取的是这个差值而不是总仿真时长这样能剔除尾部无包时间段的影响。运行它的命令awk -f stat.awk out.tr运行结果类似发送CBR包数: 17885 接收CBR包数: 17603 丢包率: 1.58% 吞吐量: 0.793 Mbps 平均端到端延迟: 8.213 ms这里吞吐量 0.793Mbps 略低于配置的 800kbps是因为丢掉了 1.58% 的包两者互相印证。如果出现吞吐量远高于链路带宽或者延迟比链路延迟还小第一反应应该是 awk 字段取错了不是算法有问题。4.3 把统计结果整理成可出图的数据awk 输出了三个数字但论文里的曲线图要有多个时间点或者多组参数。常见做法是写一个外层shell循环把不同 rate 或跳数下的 trace 跑一遍再合并成可出图的数据文件。下面是一个简单的数据整理思路for rate in 100k 300k 500k 700k 900k; do sed s/800k/$rate/ ns2_minimal.tcl tmp_$rate.tcl ns tmp_$rate.tcl awk /cbr/ {if ($1r) recv $6} END {print $rate, recv*8/4.9/1e6} out.tr throughput.dat done逻辑说明每一轮循环用 sed 把 tcl 模板里的发包速率替换成当前值生成临时脚本并运行然后从同名 out.tr 里提取接收字节数最后把速率和计算出来的吞吐量追加到 throughput.dat。这样得到的 data 文件每一行是一个速率一吞吐量点可以直接交给 gnuplot 画折线图。参数说明sed 替换的 800k 要和 tcl 文件里实际写的字符串完全一致否则替换不生效。awk 命令里的 4.9 是仿真持续时间大约是最后一个包接收时间到第一个包接收时间的差值精确值以 trace 实际为准写死数字前先 head 几个 trace 行确认时间范围。每个实验跑完一定要把 out.tr 改名归档下一个循环会覆盖它。如果你嫌 shell 循环麻烦也可以在 awk 里直接按 $2 的时间段分桶累加输出的是时间窗粒度上的吞吐量变化这适合观察拥塞发生时刻的网络行为。两类方法没有优劣论文需要横向对比参数就用前者需要展示单个实验的时间演化就用后者。5. NS2 代码避坑现场五个让我翻过车的常见问题5.1 现象终端提示 ns 找不到或 cmd 提示“不是内部或外部命令”原因没有执行环境变量设置或者用户用的是 Windows 自带的 cmd 试图直接跑 ns 命令。NS2 安装后的二进制文件在指定子目录里OS 默认不会自动扫描整个磁盘找它。解决按 2.3 节的 bash 配置把环境变量写进 ~/.bashrc执行 source 后重新打开终端。Windows 用户不要在 cmd 里硬试改用 WSL 或虚拟机里的 Linux 跑。验证方式用 which ns看到完整路径就算通过。5.2 现象脚本运行不到一秒就退出out.tr 是空文件原因tcl 脚本里 $ns run 没有执行到或者前面某个对象创建失败但错误信息被掩盖。常见情况是脚本里调用了 namtrace-all 但 nam 文件路径错误或 finish 过程在 run 之前被意外触发。解决先手动删掉输出文件然后 ns 脚本名 运行观察终端有没有输出 error。很多 NS2 脚本错误只有一行提示比如 invalid command name顺着提示行号往上看就能找到位置。out.tr 是空的优先检查 trace-all 和 namtrace-all 两个命令的文件路径是否可写目录不存在时 NS2 会静默失败。5.3 现象nam 窗口打开但界面全黑节点一个都看不见原因nam 文件里没有节点坐标信息。NS2 节点创建后不会自动获得坐标需要手动用 $n set X_ $n set Y_ $n set Z_ 赋值。从复杂脚本中抽出的 nam 文件常因为坐标语句被删而出现全黑窗口。解决在创建节点的循环里补上坐标设置比如 $node set X_ [expr random()*500]$node set Y_ [expr random()*500]。数值范围要与 nam 视图大小匹配否则节点跑到视野外依然显示黑屏。展位图上坐标单位是米无线仿真距离动辄几百米按这个量级设置即可。5.4 现象awk 统计出来的吞吐量小数完全不像真值原因字段位置取错或统计时混入了非目标业务包。NS2 不同版本 trace 格式有细微差异2.31 和 2.35 的字段偏移不完全一样另外 TCP 应用产生的 ACK 包大小只有几十字节如果按包计数统计吞吐量会得到一个不符合想象的小数字。解决先执行 head -n 5 out.tr 人工检查字段结构确认包类型在第几列、包大小在第几列。统计时加上 $5 cbr 的筛选条件只对目标业务计数。吞吐量用字节数乘 8 再除以时间带宽单位是 bps不是 pps不要拿包数直接乘包大小。5.5 现象网上抄来的脚本在 NS2.35 上报 invalid command name原因脚本版本或依赖类不匹配。ns2.rar 包里很多脚本来自 NS2.28 或 2.31 时代使用的类名、变量名和默认参数在 2.35 里已经不同还有一种情况是从多个实验脚本里零散拼凑缺了某个必要的 Agent 或 Queue 类定义。解决先定位报错行看是哪个对象创建失败。例如报 invalid command name Application/Traffic/EXPOO说明当前安装里没有 EXPOO 流量模型换成 CBR 或检查是否漏了加载对应模块。实在找不到替代就把这条报错信息连同类名一起搜索看它在老版本里对应什么实现再做等价替换。大型脚本建议用 git 或普通 diff 记录改动正本文件备份一份改坏了随时回退这是做 NS2 实验最省心的后悔药。6. 改 NS2 核心代码做自己的协议C 源码、OTcl 注册与重新编译6.1 先定位协议代码散落在源码树哪些目录如果你拿到的 ns2.rar 里带了完整源码或者你已经解压了 ns-allinone-2.35那么改代码前先熟悉目录结构。NS2 的核心代码分类相当规整tcp/ 目录放 TCP 相关实现mac/ 目录放 802.11 和 CSMA 等 MAC 层协议routing/ 目录放 AODV、DSR、DSDV 等路由协议queue/ 目录放队列调度算法common/ 目录放 packet、agent 等基础类。我改的最多的是 routing/ 和 mac/。路由协议的邻居表维护、路由发现、路由维护逻辑都在对应目录的 .h 和 .cc 文件里MAC 层协议则关注信道状态和帧间间隔。定位时先搜类名比如 AODV 对应的文件名通常就叫 aodv.cc打开文件头部注释就能看到协议实现所属版本和作者信息。在这一步不要动 packet.h 里包头格式的代码除非你真的知道自己要加什么字段。NS2 的包头结构通过 offset 机制管理加一个字段要同步修改包追踪和序列化代码牵一发动全身。对大多数实验来说改 Agent 的发送接收逻辑就够了。6.2 添加一个新 Agent 的最小改动C 类、TclClass 注册、Makefile下面是一份最简自定义 Agent 的示例代码目标是在 tcl 脚本里能通过 new Agent/Example 创建它。它不改任何现有包头只在 recv 函数里把收到的包直接释放相当于一个能接入拓扑但内容为空的代理。// example_agent.cc #include stdio.h #include agent.h #include packet.h class ExampleAgent : public Agent { public: ExampleAgent() : Agent(PT_UDP) {} virtual void recv(Packet *p, Handler *h) { // 收到包后直接释放不转发也不统计 Packet::free(p); } }; static class ExampleAgentClass : public TclClass { public: ExampleAgentClass() : TclClass(Agent/Example) {} TclObject* create(int, const char*const*) { return (new ExampleAgent); } } class_exampleagent;逻辑说明ExampleAgent 继承自 Agent 基类构造函数传入 PT_UDP 表示这是一个 UDP 类型的代理。recv 是收到包时的回调这里只调用 Packet::free 释放内存不产生任何后续行为。底部的 ExampleAgentClass 是 NS2 的 OTcl 绑定TclClass 构造参数里的字符串 Agent/Example 决定了脚本里如何实例化它。参数说明类名和 tcl 名称可以不同但建议保持一致省去人在代码和脚本两头猜名字的麻烦。包类型参数 PT_UDP 要让 Agent 的构造函数获得正确的包类型映射否则 trace 文件里的包类型标识会显示异常。接下来要把这个文件加进编译体系。第一步把 example_agent.cc 放到 ns-2.35 源码目录下第二步编辑 Makefile.in找到 OBJ_CC 变量在合适位置追加 example_agent.o第三步运行 ./configure 和 make。make 时间取决于机器性能几分钟到十几分钟都正常编译完成后再执行cd ~/ns-allinone-2.35/ns-2.35 ./configure make配置和编译完成后写一个 tcl 冒烟测试脚本验证新 Agent 能创建并与现有节点接线。我用下面这段验证它能跑通说明注册无误。set ns [new Simulator] set n0 [$ns node] set n1 [$ns node] $ns duplex-link $n0 $n1 1Mb 10ms DropTail set a0 [new Agent/Example] set a1 [new Agent/Null] $ns attach-agent $n0 $a0 $ns attach-agent $n1 $a1 $ns connect $a0 $a1 $ns at 0.5 exit $ns run验证时输出没有 invalid command name 即通过不用纠结这条测试本身有没有产生统计效果它的价值只在于确认 Agent/Example 已经被系统识别。如果真的出现错误优先检查 make 日志里 example_agent.cc 有没有被编译进去Makefile.in 的 OBJ_CC 遗漏是最常见的情况。6.3 重新 make 并验证改动生效改完 C 代码后最怕的不是编译报错而是 tcl 脚本还在用旧版本的 Agent 类名。确认改动生效的唯一硬标准是 make 完成后的那个 ns 二进制能运行 new Agent/Example 对应脚本。如果修改的是已有协议比如把 aodv.cc 里的 Hello 周期从 1 秒改成 2 秒验证方式更直接跑同样的场景看 trace 文件里 Hello 包出现的时间间隔是否变成 2 秒。我习惯在 make 之前先把旧二进制做个备份cp ns ns_bak这样新代码跑出诡异结果时能一键回退到旧版本定位是代码问题还是场景问题。make 失败时不要反复重跑先看第一处报错文件名和行号NS2 源码在旧编译器上的报错经常是语法老式写法引起需要加头文件或改类型转换。改代码这种事真正稳的验证是在完整跑业务场景后对拍 trace。比如你只改了一个队列长度改动前后接收端的吞吐量变了一点延迟却跳了一大截这就要怀疑是不是代码里连带改了别的参数。做 NS2 实验这几年我最大的收获就是只改一个参数跑一组实验改完先对比基准场景再改下一个。宁可多花几轮 script 执行时间也别让两个改动混在一起否则最后没有办法向自己解释结果更没有办法向审稿人解释。希望这篇笔记能帮你把 ns2.rar 里的这些老代码真正跑起来也帮你少踩几个我当年踩过的坑。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
乳腺癌图像分类最小可行数据集:PyTorch端到端实战指南 简介:本资源是一份面向深度学习初学者与医学图像分析实践者的乳腺癌症图像分类数据集,适用于二分类任务建模、模型训练与评估等典型AI医疗入门场景。数据集结构规范,按训练集(约480张)、验证集(约140张&… · 2026/9/24 0:37:06
常用机器学习算法Python源码包实战:从选型到避坑全解析 简介:面向机器学习入门与实践者的Python算法实现压缩包,覆盖概率统计中均值、方差、协方差等核心概念,并汇总《统计学习方法》里的算法要点。压缩包共38个文件,以笔记文档、Python源码、图片、文本说明和PDF电子文档为主ÿ… · 2026/9/24 0:37:00
PyBullet机械臂抓取闭环:从深度学习检测到仿真控制 简介:本资源是一套基于深度学习的平面抓取检测与机械臂控制完整仿真实现方案,面向机器人学、计算机视觉及AI控制方向的学习者与开发者,解决真实场景中抓取位姿估计与仿真闭环控制的关键问题。压缩包共1031个文件,含149个URDF模型&… · 2026/9/24 0:36:48
ESP32选型实战:S3与C3性能对比及避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:27:43
GB/T 27930-2015 BMS充电协议测试实战:从报文解析到故障注入 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:27:43
Windows 10 RECOVERY蓝屏修复全指南:引导重建与驱动定位 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:27:37
WezTerm 与 WSL 深度整合:用 Lua 打造高效 CLI 编程终端 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:27:30
Drive Composer Pro 2.9.0安装与连接ACS880实战避坑指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:27:18
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44