1. 环境准备:从零开始的正确姿势

想在 Ubuntu 22.04 上玩转 ns3-ai,第一步不是急着敲命令,而是把地基打牢。我见过太多新手一上来就照着某个教程猛敲 sudo apt install,结果装了一堆用不上的包,或者版本对不上,后面编译 ns3 或者 ns3-ai 的时候各种稀奇古怪的错误就冒出来了,折腾半天还得重头再来。所以,咱们先花点时间,把准备工作做扎实,后面才能一路绿灯。

首先,你得有个干净的 Ubuntu 22.04 系统。如果是虚拟机或者新装的系统,那最好不过。如果是在用了很久的系统上操作,建议先更新一下软件源,确保我们安装的都是官方维护的最新稳定版软件包。打开终端,输入 sudo apt update && sudo apt upgrade -y,让系统先自己更新到最新状态。这一步看似简单,但能避免很多因为基础库版本过旧导致的兼容性问题。

接下来是 Python 环境。ns3-ai 强烈推荐使用 Python 3.11,并且官方文档明确建议用 Conda 来管理一个独立的环境。这可不是为了增加复杂度,而是血泪教训换来的经验。系统自带的 Python 3.10 或者你之前装的其他版本的 Python,可能会和 ns3-ai 依赖的某些 C++ 库产生微妙的冲突,尤其是后面会遇到的 GLIBCXX 问题,很多都源于此。所以,咱们老老实实用 Conda。如果你还没安装 Miniconda 或 Anaconda,去官网下载对应 Linux 的安装脚本,bash Miniconda3-latest-Linux-x86_64.sh 一路安装就行。安装完成后,创建一个名为 ns3ai_env 的虚拟环境,指定 Python 版本为 3.11:conda create -n ns3ai_env python=3.11。创建完成后,用 conda activate ns3ai_env 激活它。记住,之后所有操作,只要终端开着,就确保这个环境是激活状态,这是成功的关键之一。

然后就是安装一大堆的编译依赖和工具了。这里我结合官方文档和自己踩的坑,整理了一份更稳妥的安装列表。你可以一次性复制粘贴执行,也可以分步来。注意,我们是在刚刚激活的 ns3ai_env 环境下,但安装系统包需要用 sudo。

sudo apt install -y g++ python3 cmake ninja-build git ccache
sudo apt install -y python3-pip
python3 -m pip install --user cppyy
sudo apt install -y gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3
sudo apt install -y python3-setuptools
sudo apt install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
sudo apt install -y openmpi-bin openmpi-common openmpi-doc libopenmpi-dev
sudo apt install -y mercurial unzip
sudo apt install -y gdb valgrind
sudo apt install -y clang-format
sudo apt install -y doxygen graphviz imagemagick
sudo apt install -y texlive texlive-extra-utils texlive-latex-extra texlive-font-utils dvipng latexmk
sudo apt install -y python3-sphinx dia
sudo apt install -y gsl-bin libgsl-dev libgslcblas0
sudo apt install -y tcpdump
sudo apt install -y sqlite sqlite3 libsqlite3-dev
sudo apt install -y libxml2 libxml2-dev
sudo apt install -y libgtk-3-dev
sudo apt install -y vtun lxc uml-utilities
sudo apt install -y libboost-all-dev
sudo apt install -y pybind11-dev
sudo apt install -y protobuf-compiler libprotobuf-dev

这一长串命令看着吓人,但其实都是 ns3 编译和运行可能用到的库,从编译工具链、图形界面支持、并行计算、文档生成到网络工具,一应俱全。一次性装完,能最大程度避免后续因为缺少某个 -dev 开发包而编译失败。安装过程可能需要一点时间,喝杯咖啡等着就好。

2. 获取与构建 ns-3:避开版本陷阱

依赖装好了,Python 环境也准备好了,现在可以请出主角 ns-3 了。这里有个关键点:不要直接去下载某个特定的 ns-3 压缩包。官方推荐且最不容易出错的方式,是使用 ns-3-allinone 这个打包好的安装脚本工具。它会帮你处理依赖、下载指定版本的 ns-3 源码并完成初步配置。我们找一个合适的工作目录,比如在家目录下创建一个 workspace 文件夹。

cd
mkdir -p workspace
cd workspace
git clone https://gitlab.com/nsnam/ns-3-allinone.git
cd ns-3-allinone

进入 ns-3-allinone 目录后,运行 python3 download.py。这里就和一些老教程不一样了。以前这个脚本可能会让你选择版本,但现在(根据我2024年中的实测)它默认下载的就是当时最新的稳定版,比如 ns-3.45。这其实是好事,避免了手动选择版本可能带来的未知问题。脚本会自动下载 ns-3 核心代码以及一些常用的辅助模块。下载完成后,目录结构大概是这样的:ns-3-allinone 目录下会有 ns-3.45(版本号可能不同)、bake、netanim 等子目录。

现在进入正题:编译 ns-3。重要提示:新版本的 ns-3 已经全面转向 CMake 构建系统,废弃了旧的 Waf 工具。所以如果你看到任何使用 ./waf 的教程,请直接忽略,那已经过时了。ns-3 团队提供了一个名为 ns3 的 CMake 包装脚本,使得命令行操作和以前类似。我们进入 ns-3 源码目录进行配置和编译。

cd ns-3.45
./ns3 clean  # 如果是首次安装,这步可省略,但养成好习惯
./ns3 configure --build-profile=optimized --enable-examples --enable-tests

configure 这一步会检查所有依赖是否满足,并生成构建配置。--build-profile=optimized 表示启用优化编译,这样生成的仿真程序运行速度更快。--enable-examples 和 --enable-tests 则是启用示例和测试,对于我们学习和验证安装很有帮助。如果一切顺利,你会看到一大段输出,最后是一个 Summary of ns-3 settings 的表格,里面列出了所有将要构建的模块。请仔细检查这里有没有明显的错误提示,比如某个模块因为缺少依赖而无法构建(状态为 OFF (missing dependency))。只要核心的 core、network、internet 等模块是 ON 的,一般问题不大。

配置成功后,就可以开始编译了。命令很简单:./ns3 build。这个过程会比较漫长,取决于你的电脑 CPU 性能,可能要十几分钟到半小时。你可以去忙点别的。编译完成后,强烈建议运行一下测试套件,来验证 ns-3 本身安装是否正确:./test.py。这个测试会跑上千个单元测试,全部通过当然最好,如果有少数几个测试失败(特别是某些非核心模块的),有时也能接受,但核心模块的测试必须通过。如果出现大面积失败,那说明前面的依赖安装或配置步骤可能有问题,需要回头检查。

3. 集成 ns3-ai 模块:重命名是关键

ns-3 本身安装测试没问题了,现在我们来把“AI大脑” ns3-ai 装进去。ns3-ai 是一个第三方贡献模块,需要放到 ns-3 的 contrib 目录下进行编译。操作步骤不复杂,但有一个极其关键的细节,很多教程没强调或者已经过时,导致后面编译失败。

首先,进入 ns-3 的 contrib 目录,然后从 GitHub 克隆 ns3-ai 的仓库:

cd contrib
git clone https://github.com/hust-diangroup/ns3-ai.git

克隆下来后,你会得到一个 ns3-ai 文件夹。请注意,接下来必须将这个文件夹改名为 ai。这是因为 ns-3 的模块加载机制要求 contrib 目录下的子目录名必须与模块名严格一致,而该模块在 CMake 系统里注册的名字就是 ai。如果不改名,后续 ./ns3 configure 时根本找不到这个模块,自然也就无法编译。我当初就是在这里卡了好久,一直纳闷为什么模块列表里没有 ai。

mv ns3-ai ai  # 重命名文件夹

改名之后,我们需要退回 ns-3 的主目录,重新配置和编译,让构建系统识别并包含这个新的 ai 模块。

cd ../..  # 退回到 ns-3.45 目录
./ns3 clean  # 清理之前的构建
./ns3 configure --build-profile=optimized --enable-examples --enable-tests

再次查看配置摘要 Summary of ns-3 settings,这次你应该能在 Modules configured to be built: 列表里找到 ai 模块了。这是一个重要的成功标志。确认后,再次执行编译:./ns3 build。

3.1 处理编译中的“拦路虎”

这次编译很可能会出错!别慌,这是常态,尤其是第一次安装。错误信息通常会指向 ns3-ai 自带的示例程序(examples)。我遇到的情况是,multi-bss 和 rate-control 这两个例子编译不过。其根本原因是这些示例可能依赖了某些尚未正确安装的库,或者其代码与当前 ns-3 版本有细微的不兼容。对于我们的主要目标——搭建 ns3-ai 环境本身——来说,这些示例并非必需。最直接的解决办法就是暂时“绕过”它们。

首先,我们直接删除这两个有问题的示例目录(放心,这不会影响 ns3-ai 核心模块的功能):

rm -rf contrib/ai/examples/multi-bss
rm -rf contrib/ai/examples/rate-control

其次,需要修改 contrib/ai/examples/CMakeLists.txt 文件,把编译系统对这两个子目录的引用注释掉。用你喜欢的文本编辑器打开这个文件,找到类似下面的几行:

add_subdirectory(a-plus-b)
add_subdirectory(rate-control)
add_subdirectory(rl-tcp)
add_subdirectory(lte-cqi)
add_subdirectory(multi-bss)

将其修改为:

add_subdirectory(a-plus-b)
# add_subdirectory(rate-control)
add_subdirectory(rl-tcp)
add_subdirectory(lte-cqi)
# add_subdirectory(multi-bss)

保存文件后,再次运行 ./ns3 build。这次编译应该就能顺利完成了。你会看到输出中 ai 模块被成功构建。至此,ns-3 和 ns3-ai 的 C++ 部分就安装好了。

4. 配置 Python 接口与环境变量

C++ 部分搞定了,但 ns3-ai 的精髓在于高效的 C++/Python 联合仿真。我们需要安装对应的 Python 接口包,并处理一个非常经典的兼容性问题。

首先,确保你还在 ns3ai_env 这个 Conda 虚拟环境中。然后,在 ns-3 的主目录下,安装 ns3-ai 提供的 Python 工具包和 Gym 接口包。注意路径的写法:

pip install -e contrib/ai/python_utils
pip install -e contrib/ai/model/gym-interface/py

-e 参数代表以“可编辑”模式安装,这样如果你修改了这些 Python 包的源码,无需重新安装就能生效。安装完成后,我们可以用一个最简单的例子来测试整个环境是否工作。我们使用 a-plus-b 例子的 Gymnasium 版本。

# 安装 Gymnasium,这是 OpenAI Gym 的一个维护更活跃的分支
pip install gymnasium

# 在 ns-3 主目录下,编译 a-plus-b 的 Gym 版本目标
./ns3 build ns3ai_apb_gym

# 进入该示例的 Python 脚本目录
cd contrib/ai/examples/a-plus-b/use-gym
# 运行测试脚本
python apb.py

如果幸运的话,你会看到一串 set: x,x; get: x; 的输出,这表示仿真在运行,C++ 和 Python 之间通过共享内存通信成功。但更可能的情况是,你会遇到一个经典的错误:

ImportError: ... /libstdc++.so.6: version `GLIBCXX_3.4.32' not found ...

这个问题困扰了无数人。它的根源是:Conda 环境自带的 libstdc++.so.6 库版本比较旧,不包含 GLIBCXX_3.4.32 这个符号。而我们在 Ubuntu 22.04 上编译 ns-3 时,编译器(g++)使用的是系统更新版本的 C++ 标准库。当 Python 模块(通过 cppyy 等)尝试加载编译好的 ns-3 模块时,它链接到了 Conda 环境里的旧版库,于是就找不到所需的符号了。

解决方法是告诉系统,优先使用我们 Ubuntu 22.04 自带的、更新的系统库。不要尝试去升级 Conda 里的库,那可能会破坏 Conda 环境。我们采用环境变量 LD_PRELOAD 来“劫持”库的加载。

首先,检查一下系统库是否确实包含所需的版本:

strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.32

如果这条命令有输出(显示 GLIBCXX_3.4.32),说明系统库是够新的。那么,在运行你的 Python 仿真脚本之前,先设置这个环境变量:

export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6
python apb.py

你应该就能看到成功的仿真输出了。为了避免每次运行脚本都要手动输入这个命令,你可以把它写到你的 Shell 配置文件(如 ~/.bashrc 或 ~/.zshrc)里,但更推荐的做法是在你的 Python 仿真脚本的开头,通过 os.environ 来设置,或者写一个简单的启动脚本(wrapper script)来设置环境变量并启动 Python。

5. 实战排错与进阶配置

环境搭起来了,能跑通例子了,但在实际开展自己的研究项目时,你肯定还会遇到一些坑。这里我分享两个最常见的问题和我的解决经验。

第一个坑:NumPy 版本与接口过时。 当你运行一些 ns3-ai 的例子或自己写的代码时,可能会遇到这样的错误:AttributeError: module 'numpy' has no attribute 'float'。这是因为在 NumPy 1.20 之后,np.float、np.int 等被弃用,并在更高版本中移除。而 ns3-ai 的部分早期代码可能还在使用这些旧属性。

错误信息通常会告诉你出错的文件位置,例如 .../ns3ai_gym_env/envs/ns3_environment.py。你需要打开这个文件,找到类似下面的代码段:

if mtype == pb.INT:
    mtype = np.int
elif mtype == pb.UINT:
    mtype = np.uint
elif mtype == pb.DOUBLE:
    mtype = np.float
else:
    mtype = np.float

将其修改为使用 Python 内置类型或 NumPy 的新类型:

if mtype == pb.INT:
    mtype = int  # 或 np.int32/np.int64,根据数据大小决定
elif mtype == pb.UINT:
    mtype = np.uint  # np.uint 在较新版本可能仍可用,若报错可改为 np.uint32/64
elif mtype == pb.DOUBLE:
    mtype = float  # 或 np.float64
else:
    mtype = float

保存文件后,由于我们是以 -e 可编辑模式安装的,修改会立即生效,无需重新安装。

第二个坑:CMake 缓存导致的模块“消失”。 有时候,你修改了 contrib/ai 目录下的文件(比如添加了自己的模块),或者调整了 CMakeLists.txt,然后重新 ./ns3 configure 时,发现输出的模块列表里竟然没有 ai 了!这通常是因为 CMake 的缓存(在 build 目录下的 CMakeCache.txt)没有正确更新,它误以为 ai 模块的配置条件不满足(比如之前编译失败过)。

遇到这种情况,最彻底(虽然有点慢)的解决方法是:

  1. 备份好你添加到 contrib/ai 目录下的个人项目代码。
  2. 执行一次深度清理:./ns3 clean。
  3. 甚至可以直接删除整个 build 目录:rm -rf build。
  4. 重新执行 ./ns3 configure ... 和 ./ns3 build。

这能确保从一个干净的状态重新构建。虽然耗时,但往往能解决很多诡异的缓存问题。

关于添加自己的项目: ns3-ai 的设计使得集成自己的 AI 仿真项目很方便。标准的做法是,在 contrib/ai/examples 目录下,参照 a-plus-b 或 rl-tcp 的例子,创建你自己的项目文件夹。里面需要包含 CMakeLists.txt 来定义如何编译 C++ 部分,以及 Python 脚本。最关键的一步是,别忘了把你新建的目录名,添加到 contrib/ai/examples/CMakeLists.txt 文件的 add_subdirectory() 列表中。这样,下次编译时,你的项目就会被包含进去。这种组织方式既清晰,又能直接利用 ns3-ai 框架提供的通信机制。

更多推荐