说起来,这阵子折腾那个ns3fb可真是费了我不少劲。我本来是想搞个无线传感器网络的仿真,想着既然ns-3搞这块儿挺好的,加上又看到了ns3fb这个东西,就想着说不定能搞出点花样来。
我就是兴冲冲地把代码拉下来,想着按照网上的教程,一步一步来,应该没啥大问题。结果,第一个大坑就给我来了个下马威,编译都过不去!我照着官方文档,把那些什么gcc、python、boost之类的依赖都装了一遍,自以为万事俱备,结果一执行那个`./waf configure`,就给我报错,说这文件找不到,那库不对劲。
我当时就傻眼了,心想,我这都是按照步骤来的呀,怎么就不行了?我左看右看,把那些报错信息截图下来,挨个在论坛上搜。你别说,这一搜还真发现不少哥们儿也遇到过类似的问题。原来问题出在依赖的版本上。平时装啥都喜欢装最新的,觉得新版本肯定结果ns3fb这东西,对特定版本的依赖还挺讲究。特别是那个python的版本,我用的是新的,它默认好像还只支持老一些的,或者说,它需要的那些库,在新版本python下安装起来更复杂,容易出岔子。
我那会儿就动手了,先是把python环境给降级,然后把那些boost库,gtk库,都按照官方推荐的“稳妥”版本重新装了一遍。这回学乖了,不再盲目追求最新。一步一步来,安装完一个就检查一下。等我把所有依赖都搞定,再跑`./waf configure`,奇迹发生了,它终于通过了!接着`./waf build`,漫长的编译过程后,终于提示成功了。那一刻,我真想给自己鼓掌,就感觉攻克了一座大山。
解决了编译问题,我开始跑一些自带的例子。小脚本跑起来没啥问题,挺顺利的。可一旦我自己动手,写了一个稍微复杂一点的拓扑结构,想加进去一些自定义的协议行为,问题又来了。我的仿真程序跑起来,就一直报错,不是内存访问越界,就是某些指针是空。我那个心,又悬起来了。
这回的排查就没那么简单了。我怀疑是我的代码逻辑有问题,毕竟第一次写这种级别的网络仿真代码。我把代码分成小块,一点点地测试,看看是哪块出了问题。我就是靠`printf`大法,在代码里到处打日志,看它到底走到哪儿挂掉的。但这种方法太笨了,日志一多,根本看不过来。后来我才想到,ns-3本身不是有自己的日志模块吗?我应该充分利用它!
于是我开始学习怎么用ns-3的`LogComponentEnable`来控制输出。我把那些可能出问题的模块的日志级别都调到了`LOG_LEVEL_DEBUG`,甚至`LOG_LEVEL_ALL`。这一开,果然很多平时看不到的细节都跑出来了。我发现很多时候不是我代码逻辑错得离谱,而是我某个参数设置错了,或者在某些对象还没完全初始化好之前,就去访问了它的成员。比如,我构建节点的时候,顺序没搞对,或者没等设备安装好就去设置它的属性。
我花了几天时间,就盯着那些日志看,然后对照着ns3fb的示例代码,一点点地修改我的程序。每次修改一小块,就重新编译跑一下。就这样,像个侦探一样,把那些隐藏在代码深处的“小鬼”一个个揪出来。我记得有一次,我就是因为在创建无线信道的时候,没有正确地把物理层和MAC层绑定起来,导致我的节点根本就发不出数据包。日志里面就会一直提示“no device found”之类的错误,但是因为信息量太大,我一开始没注意到。
还有一个让我头疼的问题,就是仿真结果不符合预期。程序跑完了,也没报错,但是统计出来的数据,比如丢包率、吞吐量,跟我理论上预期的完全不一样。那时候我就知道,肯定是在仿真配置上哪里还有猫腻。
这回我不再盲目改代码了,而是重新回去看ns3fb和ns-3关于统计和追踪的文档。我发现ns-3有很强大的追踪机制,可以把每个数据包的生命周期、每个事件的发生时机都记录下来。我开始学习怎么使用那个`Pcap`文件来抓包,用`Wireshark`来分析。我还尝试着自己写了一些自定义的追踪源(trace source),把我想关注的变量或者事件打印出来。通过这些精细化的追踪,我才发现,原来是我的RTS/CTS机制配置得有点问题,导致在特定的拥塞情况下,大量的数据包都在竞争信道,互相干扰,最终导致丢包率飙高。一开始我还以为是我自己的协议算法写错了!
这大半个月折腾下来,虽然累,但收获真的挺大的。从最开始的编译都过不去,到后来能独立分析各种日志,用Wireshark抓包,甚至定制追踪点,感觉自己对ns3fb和ns-3的理解又深了一层。这些问题看着麻烦,但一旦搞明白了,会发现很多时候都是些很基础但容易被忽略的小细节。所以说,遇到问题别急,一步一步来,多翻翻官方文档和社区论坛,总能找到解决办法的。有时候,换个角度看问题,或者用更底层的工具去分析,就能豁然开朗了。我的无线传感器网络仿真,现在跑得稳稳当当的了,数据也都能对得上。


