作者:娜一刻冻杰幸福 | 来源:互联网 | 2023-05-16 06:51
(--原创,转载请声明--)opnet是一款功能很强大的软件,可以很好的模拟各种层面的网络行为(从小的协议分析到大范围的MANET)。其库文件中包含了当前多数已经标准化的网络协议,也支持用户自定义
( --原创,转载请声明-- )
opnet是一款功能很强大的软件,可以很好的模拟各种层面的网络行为(从小的协议分析到大范围的MANET)。其库文件中包含了当前多数已经标准化的网络协议,也支持用户自定义进程模型和节点模型。opnet属于商业软件,其内部的协议实现版本比较全面和标准,不像开源的ns2和ns3,大家都在上面定制自己的协议和仿真模型,纷纷杂杂(有点像现在的android)。不过ns的开源也有它自己的好处,大家可以很方便的找到适合自己的模型,相反,opnet的商业性和付费性使得相应的应用很少,而且由于版权问题,几乎没有公布基于opnet实现的open source论坛。
opnet上手较慢,想要完全理解其内部的工作原理(如状态机跳转关系、进程间调用关系、无线阶段配置等)需要花费一段时间,尤其在opent内部定义了大量的库函数(只提供接口,看不到函数实现,这一点有时候会很麻烦),需要耐心的了解和学习,方才能够在运用时得心应手。
需要提到一点,当前市面上所有opnet的书都是翻译软件自身的帮助手册(在Help->Product Documention打开),而且有的书籍翻译较粗糙,自认为参考价值不大。我自己学习opnet的方法是 1.看东南大学培训视频(在六维上可以下载),了解软件的基本功能; 2.浏览Product Documention中的核心函数,看有哪些类型,实现了哪些功能;3.做小工程进行练习;4.进行软件开发
下面总结一下自己在使用opnet开发仿真平台过程中遇到的问题。有的问题是学习软件初期遇到的,有的是在开发过程中花费几天时间才解决的问题。现在回头来看,多数已经不是问题,但有的仍需要留心,现以星号标记其程度。
** 1.access和get
但凡涉及到access的函数都是以指针的形式访问其指向的区域,调用后不会更改指向区域的内容,如op_pk_nfd_access(),op_prg_list_access() ...
涉及到get和remove的函数会将内存中的内容取出,如op_ok_nfd_get(),op_prg_list_remove(),prg_bin_hash_table_item_remove() ...
但也有例外情况,如获取包流ici的函数op_pk_ici_get(),获取后相应的ici还附着在包上,只有调用op_pk_ici_destroy()或者重新install一下才会将原来的删除或覆盖。
* 2.ici的使用
根据网络协议的分层原则,低层协议通常是不会读取高层数据包中的内容,只是做一下封装。opnet中上下层交互的信令通常用ici来传递,即用ici来模拟层间原语。
我一般是分三步走:op_ici_create() -> op_ici_attr_set() -> op_pk_ici_set(),这样就会为每个包安装ici
在计算包大小以及goodput过程中,ici的尺寸是不会考虑在内的。
* 3.调试过程中的多条件跳转报错
<<>>
Multiple true transitions from state (idle)
问题原因:在对应的进行模型中同一时刻满足条件的状态跳转多于一个。
* 4.包域的问题
在包的编辑器中,包“域”的数据类型给定的有: integer, floating point, structure, packet, information, integer(64 bit), packet ID, or object ID,用这些类型来模拟每一册协议单元的字段或数据域。
我经常使用的是integer,struct和packet。其中的struct类型需要在头部定义一个结构体类型的数据,代表整个"域"(通常作为头部),packet一般采取inherited上层包的形式,作为数据域。注意struct域可以设置大小,但是该大小与你定义的结构体实际内存占用情况无关,只是代表协议设计中该包域的大小,不会影响程序运行,只会影响统计结果的收集。
*** 5.慎用op_pk_send_forced()函数
该函数对应的是强制无延迟的发包策略。自己多次在仿真中都出现如下问题:
<<>>
Unable to execute intrpt at process (2)
Process is already within an invocation
当时并无头绪如何解决这个问题,很幸运的是,在碰巧将op_pk_send_forced()函数改成op_pk_send()后问题消失了。就如同Product Documention函数中警示的那样,op_pk_send_forced()函数在多进程交互过程中会导致不可预期的结果。
* 6.包的分片和重组
在设计过程中,由于底层协议帧大小的限制通常要对上层的数据包分片,这就需要使用分段缓冲区。缓冲区的创建使用函数op_sar_buf_create(),该函数有两个参数:第一个参数中对应了多个常量标识符,我用到的有两个,OPC_SAR_BUF_TYPE_SEGMENT(对应分段缓冲区)和OPC_SAR_BUF_TYPE_REASSEMBLY(对应重组缓冲区),其中分段缓冲区分段后的数据还可以接着继续被分段。第二个参数也对应了多个常量标识,在分段时我用到的也是有两个,OPC_SAR_BUF_OPT_PK_BNDRY(不将分段打包成固定大小)和OPC_SAR_BUF_OPT_SEG_PAD(将数据打包成固定大小),在重组时用到的为默认参数OPC_SAR_BUF_OPT_DEFAULT。
** 7.结构体的设置与获取
get(获取)信息的时候都要取地址,如op_ici_attr_get(recv_high_iciptr, "node_id", & nid_info_get); op_pk_nfd_access (pkptr, "head block", & hb_ptr);
set(设置)的时候不用,如op_pk_nfd_set (bd_pkptr, "head block", hb_ptr, op_prg_mem_copy_create, op_prg_mem_free, sizeof (head_block)); op_ici_attr_set (iciptr, "node_id", nid_info);
* 8.关于全局和局部统计量
全局统计量(global)能够统计场景中总共收到的数据包个数,本地统计量(local)能够统计每个节点收到的数据包。在设置好统计量后将其提升到模块属性,方便选择。
**** 9.opent自动崩溃的问题
暑假回来继续使用opent,软件隔一段时间(几分钟)就会崩溃并自动关闭,出现如下问题:
unhandled vex exception
consult C:\Users\Infonet\op_admin\err_log for more details.
In OPNET,access the information for Help>Error Log>Open.
开始百思不得其解,然后尝试清理电脑中的垃圾,发现不知道在什么时候无意装了麦咖啡杀毒(一向只用360的),卸载后正常了。。一些杀毒软件也许与opnet不兼容。
** 10.三种进程间内存共享方式(就不自己总结了,转个别人写的)
a)module memory同模块共享内存:
通过函数op_pro_modmem_install()和op_pro_modmem_access()访问。为了保证process间通信机制,各个 process应当遵循shared memory的数据类型,这就要求process都要知道,因而shared memory的数据结构定义应当房子外部定义".h"文件中,并包含在每个process的header block中。shared memory一开始是没有的,是由process来决定什么时候分配以及分配多大,这些通过op_pro_modmem_access()来完成。内存的分配一般是通过op_prg_meme_alloc()来完成。
b)父子共享内存:
只有以父子关系联系在一起的process才能访问的私有共享内存。这种共享内存只能在child process由op_pro_create()产生时由op_prg_mem_alloc()分配,且不能被替换。通过 op_pro_parmem_access()访问。通过op_pro_invoke()通知对方对共享内存的内容进行的修改和,以及对内容的检查。
c)参数内存(argument memory)
将内存地址作为op_pro_invoke()的参数传给别的进程用以通信,通过op_pro_argmem_access()来完成访问。与前两个不同的是,这部分内存不是永恒的。
**** 11.关于不同进程使用同一个struct的问题
不同模块间的struct中的元素必须按照相同的顺序定义,否则不但不会报错,而且会导致读取其中元素数值的错误
解决方法:将多次使用的struct放在头文件中,每个使用该struct的进程包含一下该头文件即可。
*** 12.最后记录几个错误记录
op_ev_cancel (ack_event); //可能取消不了,因为中断已结束!!需要加测试条件 if( op_ev_pending (ack_event) == OPC_TRUE) 判断当前事件是否还存在。
list中的包发送以后就不能再发了,即使是access,也不行。
两个list不能直接赋值,要先creat,再init,再copy
为了使进程同步,在父进程的init状态就要invoke一下子进程