Qualnet的GUI运行很简单,新建打开已有场景,添加节点,设置各层协议参数,保存运行即可。如果只是用作仿真工具,这样就足够了,但若想自己开发一个协议,或者想深入了解Qualnet底层是如何运行的,那就一定要研究源代码。以下是我在开发过程中,遇到困惑时,耐下心来一步一步学习的结果。在现在看来,这些东西好像很简单,顺理成章,但学习的过程还是很费时费脑的。我是从自己开发用到的几个常用函数,往回倒推,看哪个函数调用它,那个函数还有什么其他作用,找出整个运行过程的。我在此介绍的主要是与我的研究相关的内容,没有将所有的过程都写出来,只是一个比较通用的脉络,供各位参考。
1. 起点
倒推的过程不再絮叨,直接从找到的起点前推叙述。起点位于~/libraries/wireless/src/prop_range.cpp中,里面只有一个main函数。主要代码即功能注释如下。
int main(int argc, char **argv) {
// 初始化配置文件.
IO_InitializeNodeInput(&nodeInput, true);
// 创建空分区.
partitionData = (PartitionData*)MEM_malloc(sizeof(PartitionData*));
memset(partitionData, 0, sizeof(PartitionData*));
partitionData = PARTITION_CreateEmptyPartition(0, 1);
// 读取配置文件.
IO_ReadNodeInput(&nodeInput, argv[1]);
// 读取地理信息.
terrainData.initialize(&nodeInput, true);
// 读取配置种子,初始化种子信息.
if (!seedValSet)
{
IO_ReadInt(
ANY_NODEID,
ANY_ADDRESS,
&nodeInput,
"SEED",
&wasFound,
&seedVal);
……
}
// 读取配置仿真时间.
IO_ReadString(
ANY_NODEID,
ANY_ADDRESS,
&nodeInput,
"SIMULATION-TIME",
&wasFound,
buf);
// 建立节点ID和节点ip地址的映射,为场景节点建立合法ID号.
MAPPING_BuildAddressMap(
&nodeInput,
&numNodes,
&nodeIdArray,
addressMapPtr);
// 分配节点位置数组的内存.
MOBILITY_AllocateNodePositions(
numNodes,
nodeIdArray,
&nodePositions,
&nodePlacementTypeCounts,
&nodeInput,
seedVal);
// 读取配置信息,设置节点位置.
MOBILITY_SetNodePositions(
numNodes,
nodePositions,
nodePlacementTypeCounts,
&terrainData,
&nodeInput,
seed,
simProps.maxSimClock,
simProps.startSimClock);
// 利用位置和其他信息,将节点分配至分区.
int numberOfPartitions = PARALLEL_AssignNodesToPartitions(
numNodes,
1,
&nodeInput,
nodePositions,
(const AddressMapType*) addressMapPtr);
// 利用已有的分区内存和各类参数,初始化分区.
PARTITION_InitializePartition(partitionData,
&terrainData,
simProps.maxSimClock,
startRealTime,
numNodes,
FALSE,
addressMapPtr,
nodePositions,
&nodeInput,
seedVal,
nodePlacementTypeCounts,
experimentPrefix,
simProps.startSimClock);
// 初始化传播信道.
PROP_GlobalInit(partitionData, &nodeInput);
// 利用分区信息,初始化分区内的节点
PARTITION_InitializeNodes(partitionData);
// 地理信息确认
terrainData.finalize();
return 0;
}
main函数中,通过读取配置文件,初始化了分区和节点。带IO_开头的函数都是读取配置文件的,见fileio.h,只有函数申明,没有找到定义,理解其含义就行。里面的几个重要函数,以及函数中再调用的重要函数,下面一一介绍。
2. 重要函数
2.1 分配内存并初始化节点位置相关信息
函数见~/main/mobility.cpp,主要作用是读取节点配置中的放置方式信息,分配内存并初始化节点位置和移动信息。
void MOBILITY_AllocateNodePositions(
numNodes,
nodeIdArray,
&nodePosi