omnetpp inet
http://blog.csdn.net/midie/article/details/5086983
omnetpp inet
自带了Mingw编译环境,而不再需要Visual C编译环境了。事实上,OMNeT++ 4.0也不支持使用Visual C++的编译器。在4.0版本中还加入了基于Eclipse的IDE,可以直接使用。如果需要重新编译OMNeT++,可以使用msys/msys.bat打开Shell,先使用./configure生成配置文件,然后直接make即可。
1. 在使用IDE的时候,需要在参数中设置OMNeT++的各个选项,包括OMNeT++的目录,Image的目录以及dot和doxygen的程序路径。否则在编译的时候会提示找不到相应的命令,或者说是通过了编译,但是却找不到图标来显示。如果是找不到命令如opp_makedep等,则可以将omnetpp-4.0/bin加入到系统的PATH环境变量中。
2. INET现在也已经移植到了4.0版本下,并且从MF模块中借鉴相关的实现,现在已经支持无线协议。现在可以从http://github.com/inetmanet/inetmanet/tree/master上下载及时更新后的代码。将代码解压后放在OMNeT++的目录下,直接make即可。目录下的buildMakefiles可以用来生成Makefile文件,包括两种,一种是生成dll(Linux下为.so)的,另一种是生成.exe的。如果在运行的时候没有发现对应的可执行文件或者动态链接库,则可以使用相应的Makefile,并重新make即可。
3. 在编译或链接INET的时候,有可能出现无法找到pcap_等符号,作者在邮件列表中也注意到了这个问题,但是我下载下来的时候还没有进行修改,所以直接将那些相应的源代码进行了屏蔽,并没有出现什么问题。可能以后如果需要和外界进行交互的时候再看吧。如果运行的时候出现无法加载libpcap这样的字样,则去下载一个winpcap安装上吧。
4. 在通过命令行启动仿真程序的时候,发现图像无法加载。这是因为我修改了OMNeT++所在目录的盘符,而现在的代码还是使用原来的盘符下的目录来加载图像,重新编译了也无济于事。猜想可能是原来编译的时候对图像的目录进行了设置。找了半天无果,干脆直接到源代码中去看看。结果在src/tkenv/tkenv.cc的Tkenv::run中看到了可以设置图像的路径。将OMNETPP_IMAGE_PATH加入到系统的环境变量中,问题得到解决。
OMNeT++通过NED语言来对网络系统进行描述。NED语言中包含着对信道、模块、节点和网络的完整描述,可以参见OMNeT++参考文档的第三章。在实际的网络仿真中,总是会首先描述一些特定形状和特性的网络。一般说来,网络拓扑结构包括两种,一种是平面(flat)结构,另外一种是层次化(Hierarchy)结构。由于OMNeT++采用的是层次化的模块构建,所以层次化的网络拓扑可以通过平面的拓扑结构来生成。在这里,对常见的几种网络拓扑结构进行描述。更多的代码可以参见OMNeT++包中sample目录下的neddemo。
在构建平面拓扑结构的时候,主要考虑的是各个节点之间的关系。对于规则的拓扑结构来说,节点之间的连线是有关系的。在下面的描述中,主要的是对这种关系进行梳理。
(1) 二叉树结构
一个二叉树结构中的节点包含有三个接口,分别对应父节点和左右子节点。这里用fromUpper和downLeft、downRight来表示。对于高度为height的二叉树结构,其节点之间的关系可以表示如下。
- for i=0..2^height-2, for j=0..2^height-2 {
- node[i].downLeft <--> node[j].fromUpper if j==2*i+1;
- node[i].downRight <--> node[j].fromUpper if j==2*i+2;
- }
这是OMNeT++中的另外一种表示方法(没有了if条件表达式)。
- for i=0..2^(height-1)-2 {
- node[i].downLeft <--> node[2*i+1].fromUpper;
- node[i].downRight <--> node[2*i+2].fromUpper;
- }
生成的拓扑结构如下所示。从图中可以看到,最终生成了一个二叉树结构。这里的节点并没有显示成从上至下的结构,而是系统自动采用了一种合适的方法来表达。如果需要修改的话,则还需要对接点的位置进行约定。可以参见NED的描述文件。
(2) 链结构
另外一种很常见的网络拓扑结构就是线性结构,就像一条链一样串起来。这种结构在OMNeT++中是很容易描述的。下面的代码这个实现。
- for i=0..n-2 {
- node[i].right <--> node[i+1].left;
- }
生成的网络拓扑结构如下所示。
(3)完全图
完全图是一个节点和网络中的所有节点都有连接。拓扑结构描述如下所示。
- for i=0..(n-2), for j=(i+1)..(n-1) {
- node[i].g[j] <--> node[j].g[i];
- }
其中, node 表示节点,而这里的 g[] 表示门向量。这里通过二重循环将节点之间的所有接口都连接了起来。另外,这里采用了位置描述符来对网络进行描述,从而让整个网络成为一个环形。
@display("p=,,ring");
生成的完全图如下所示。
(4)星形图
这种网络拓扑结构是所有节点通过一个中心节点连出去。这种网络的创建并没有什么特殊的地方,一般构建两类节点:中间节点和终端节点,然后将所有的终端节点和中心节点相连即可。
生成的拓扑结构如下所示。
(5)网格网格拓扑结构
这种网络拓扑结构也很常见。这种拓扑结构中的节点包含有四个接口,分别连接上下左右的节点。节点之间的连接关系如下所示。
- for i=0..height-1, for j=0..width-1 {
- node[i*width+j].down <--> node[(i+1)*width+j].up if i!=height-1;
- node[i*width+j].right <--> node[(i*width+j)+1].left if j!=width-1;
- }
生成的网格图如下。
(6)蜂窝网络拓扑结构
这是上面网格拓扑结构的一个变种,一般可以用于蜂窝网路中。这里的节点最多包含有三个接口,其连接关系如下面的NED代码所示。
- for i=0..num-1 {
- node[i].port++ <--> node[i+1].port++ if i<num-1 && i%(2*cols+2)!=2*cols;
- node[i].port++ <--> node[i+2*cols+1].port++ if i<num-2*cols-1 && i%2==0;
- }
(7)随机拓扑结构图
有些时候需要随机生成网络拓扑结构,这在OMNeT++中是比较容易实现的。下面就是一种实现的方法。
- for i=0..n-1, for j=0..n-1 {
- node[i].g++ <--> node[j].g++ if i!=j && uniform(0,1)<connectedness;
- }
代码中connectedness用来控制节点的连接度,1表示连接所有的其他节点。减小此值将减少网络中出现的边数。一种随机图如下所示(connectedness=0.15)。
上面介绍的是比较常见的一些网络拓扑结构。在实际使用中,这些网络拓扑在针对特定问题的简化版本是可以的,但是当网络变得复杂后,这样的拓扑生成还是不行的。此时最好是采用专门的拓扑生成器,来生成网络拓扑。另外,这里介绍的都还是有线网络中的拓扑结构,还没有涉及到无线网络的拓扑生成。
现在的 OMNeT++4.0 已经将这里的结果集成了进去,推荐使用 EV 来输出日志信息。具体的定义见 include/cenvir.h文件。这篇文章详细的讨论了如何设置 EV ,具有普遍的借鉴作用。
ev<< 语句可以用来打印信息从而了解到仿真模型正在做什么。这在进行调试和理解模型运行的时候是很有用的。现在的问题是,当模型需要运行很长时间的时候, ev<< 语句将会消耗大量的 CPU 周期。这个时候该怎么办呢?
本文将介绍如何高效率的进行记录,并且同时介绍如何创建 log channels 或者调试 channels 。
在 Cmdevn 环境下,当设置 express-mode=true 的时候,输出将会被丢弃而不会被打印,从而使得执行可以更快。但是实际上, ev<< 语句还是会带来一些开销。这种速度的减小可能不会被注意到,但是影响却是很大的。这里的问题是, OMNeT++将只会丢弃也就是不打印已经转换为文本格式的字符串。举个例子,如下面的语句:
- ev << "Average bit/sec is: " << totalBits/simTime() << "n";
- ev << "Average bit/sec is: " << totalBits/simTime() << "n";
即使是在极速模式下, simTime() 将会被调用,浮点数除法也会被执行。结果将会被转换为字符串并存储在缓冲区中,而这里的缓冲区则会被丢弃。很遗憾的是, OMNeT++ 核心没有办法阻止这种事情发生,因为这是 C++ 的工作方式。
这时候该怎么办呢?一种常见的方式是采用 #ifdef 。
- #ifdef DEBUGGING
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- #endif
- #ifdef DEBUGGING
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- #endif
这并不坏,但是却有一个很严重的问题:在切换打印输出的时候必须重新编译所有的文件。根据墨菲定律(有可能出错的事情,就会出错,Anything that can go wrong will go wrong),当人们需要输出的时候往往看不到有输出。另外,代码中满含有 #ifdef 也不是一个好办法。随后想到的就是如何在编译的时候就将是否输出考虑到,下面是一个示例代码。
- if (debugging)
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- if (debugging)
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
这比前面要好一些。 if 语句的开销是比较小的。这样,就可以在初始化的时候通过 debugging 变量来决定是否输出信息。
- debugging = par("debugging").boolValue();
- debugging = par("debugging").boolValue();
这种做法还不是很方便,因为我们需要手工维护输出的状态。有些人会发现此值可以在调试中进行动态设置,但是这还不能令人满意。为什么不能让代码知道我们是否需要记录呢?
实际上,我们可以回答这个问题。一般的, OMNeT++ 知道我们何时需要进行记录:不在极速模式下的时候。幸运的是, ev 对象可以知道这点,所以现在最新的代码如下。
- if (!ev.disabled())
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- if (!ev.disabled())
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
几乎就是这样了。现在的问题是需要为每个 ev 输出增加一个 if 语句。有经验的 C/C++ 程序员将会马上想到采用宏来产生精炼的代码。第一次尝试:
- #define EV if (!ev.disabled()) ev // *** DANGEROUS!***
- ...
- EV << "Average bit/sec is: " << totalBits/simTime() << endl;
- #define EV if (!ev.disabled()) ev // *** DANGEROUS!***
- ...
- EV << "Average bit/sec is: " << totalBits/simTime() << endl;
注意,这里的宏将会产生很严重的问题。考虑一下下面的代码:
- if (totalBits>1000)
- EV << "Average bit/sec is: " << totalBits/simTime() << "n";
- else
- EV << "Not enough data yet" << endl;
- if (totalBits>1000)
- EV << "Average bit/sec is: " << totalBits/simTime() << "n";
- else
- EV << "Not enough data yet" << endl;
这段代码并不会按照设想的那样工作。当我们宏替换完成并重新缩进代码后,将得到下面的代码:
- if (totalBits>1000)
- if (!ev.disabled())
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- else if (!ev.disabled())
- ev << "Not enough data yet" << endl;
- if (totalBits>1000)
- if (!ev.disabled())
- ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- else if (!ev.disabled())
- ev << "Not enough data yet" << endl;
所以这里的代码将永远不会打印出“ Not enough data ”。
最好是忘记上面的 EV 定义,因为这很容易会使得你栽在上面。即使是在这个宏定义中加上一对括号也不能解决问题,因为打印参数将会在括号之外。看起来这个问题没法修复。
尽管如此,让我们来看看下面这个版本:
- #define EV ev.disabled() ? ev : ev
- ...
- EV << "Average bit/sec is: " << totalBits/simTime() << endl;
- #define EV ev.disabled() ? ev : ev
- ...
- EV << "Average bit/sec is: " << totalBits/simTime() << endl;
这看起来有点奇怪。这里的宏定义看起来没有区别(无论是为 true 或者是 false ),而且这和所有 C 语言教科书中所倡导的(宏如果需要扩展成表达式需要加上圆括号)相违背。但是确实这个宏是可以工作的。现在 EV<< 将会变成一个简单的表达式。
- ev.disabled() ? ev : ev << "Average bit/sec is: " << totalBits/simTime() << endl;
- ev.disabled() ? ev : ev << "Average bit/sec is: " << totalBits/simTime() << endl;
这和下面的相同(注意符号的优先级) :
- ev.disabled() ? ev : (ev << "Average bit/sec is: " << totalBits/simTime() << endl);
- ev.disabled() ? ev : (ev << "Average bit/sec is: " << totalBits/simTime() << endl);
这时候,当 ev 被禁止的时候(条件为 true ),这只是简单的一个 ev 对象的引用(这最终将会被编译器所优化,而不会产生任何的 CPU 指令);当 ev 启用的时候(条件为 false ),将会被还原成原始的 ev<< 语句。这正是我们所需要的。证明这里的 EV 定义在任何使用场景中都是可行的,这可以作为练习。无论是否有 if 语句,或者是还有一个 ?: 操作符,或者是其他的场景,这都是适用的。
实际上,上面 EV 的 ?: 版本并不能在 VC++ 7.0 中通过编译(因为在 VC++ 7.0 中需要?:三元操作符的第二个和第三个参数的类型是一样的,而不会做默认的转换)。所以在 VC7 中的版本是这样的:
- #define EV ev.disabled() ? (std::ostream&)ev : ev
- #define EV ev.disabled() ? (std::ostream&)ev : ev
(译者注:实际上,由于现在最新的 OMNeT++ 4.0 并不支持使用 VC 编译器进行编译,所以也没有采用这样的方式)。
如果你没有用过 log4j 或者是 C++ 中类似的工具( log4Cpp , libCWD 等),那你有可能错过调试管道或者说是日志管道。简单地说, channels 是针对快速滚动日志问题的答案(因为你几乎不可能在日志的海洋中找到有用的信息)。你的代码日志将会记录到多个管道中,而在调试的时候可以只关注自己感兴趣的管道。有两个标准可以用来区分管道日志: topic 和调试级别(如 detail, info, warnings )。其中第三个标准是位置(模块位置),这已经被 OMNeT++ 内置了。可以通过查看模块的输出来得到你想要的信息。
一个比较好的消息是通过上面的 EV 定义,可以用来简单的模拟日志管道。当书写一个 IP 模块的时候,检查下面的定义:
- #define fwdingEV (ev.disabled()||!fwdingChannel) ? (std::ostream&)ev : ev
- #define localEV (ev.disabled()||!localChannel) ? (std::ostream&)ev : ev
- #define mcastEV (ev.disabled()||!mcastChannel) ? (std::ostream&)ev : ev
- #define dropEV (ev.disabled()||!dropChannel) ? (std::ostream&)ev : ev
- #define fwdingEV (ev.disabled()||!fwdingChannel) ? (std::ostream&)ev : ev
- #define localEV (ev.disabled()||!localChannel) ? (std::ostream&)ev : ev
- #define mcastEV (ev.disabled()||!mcastChannel) ? (std::ostream&)ev : ev
- #define dropEV (ev.disabled()||!dropChannel) ? (std::ostream&)ev : ev
上面的定义提供了四个日志信道( wdingEV, localEV, mcastEV, dropEV ),可以通过单独设置fwdingChannel, localChannel, mcastChannel, dropChannel 布尔变量的值来进行开关。可以像下面这样使用日志管道。
- ...
- EV << "packet received" << endl;
- ...
- if (destAddress.isMulticast())
- {
- mcastEV << "multicast packet, addr=" << destAddress << endl;
- ...
- }
- ...
- if (!routeFound)
- {
- dropEV << "unroutable packet, dropping" << endl;
- delete datagram;
- }
- ...
- ...
- EV << "packet received" << endl;
- ...
- if (destAddress.isMulticast())
- {
- mcastEV << "multicast packet, addr=" << destAddress << endl;
- ...
- }
- ...
- if (!routeFound)
- {
- dropEV << "unroutable packet, dropping" << endl;
- delete datagram;
- }
- ...
omnetpp inet的更多相关文章
- vmware 虚拟机通信拿不到 inet addr 的解决办法
我在虚拟机上安装完红帽之后,使用ifconfig命令来看网卡的IP,但是,输入命令之后,eht0里面只有 inet6 addr 而没有 inet addr,不多说,上图. 解决办法如下:打开 虚拟机设 ...
- iface eth0 inet dhcp
- How To: Perl TCP / UDP Socket Programming using IO::Socket::INET
http://www.thegeekstuff.com/2010/07/perl-tcp-udp-socket-programming/ In this article, let us discuss ...
- GNU INET SOCKET
Linux程序设计入门 - socket/inetd programming UNIX Socket Programming基本上是一本书名.Socket programming其实需要相 当程度的基 ...
- arpa/inet.h所引起的Segmentation fault及网络编程常见的头文件
最近在学习Linux网络编程方面的知识,感觉还是有些困难.主要是对协议过程的理解,还有socket的API的理解不够深刻.今天复习编写了一个TCP的服务端和客户端的程序实现client.c从命令行参数 ...
- 虚拟机安装centos发现inet为127.0.0.1,导致Xshell连接不上
问题如标题所示: 设置网卡开机自动启动: 实质linux是看一个网卡文件的配置,就是/etc/sysconfig/network-scripts/ifcfg-eth0 (这个文件名看你网卡名称而异,具 ...
- IP:192.168.21.173 子网掩码:255.255.255.0 网关:192.168.21.2 DNS:8.8.8.8 8.8.4.4 1、设置IP地址、网关 ee /etc/rc.conf #编辑 ifconfig_em0="inet 192.168.21.173 netmask 255
IP:192.168.21.173子网掩码:255.255.255.0网关:192.168.21.2DNS:8.8.8.88.8.4.41.设置IP地址.网关ee /etc/rc.conf #编辑if ...
- UNP总结 Chapter 12~14 IPv4与IPv6的互操作性、守护进程和inet超级服务器、高级I/O函数
一.IPv4与IPv6的互操作性 1.IPv4客户与IPv6服务器 拥有双重协议栈的主机的一个基本特性就是:其上运行的IPv6服务器既能应付IPv4客户,又能应付IPv6客户.这是通过使用IPv4映射 ...
- 虚拟机安装cenos7后ifcfg看网卡无inet地址掩码等信息
在虚拟机安装centos7,进入系统使用ifconfig命令时,只有lo网卡( 127.0.0.1的ip地址)和eno16777736网卡,而且此网卡没有inet地址.掩码等信息. 这时候查看/etc ...
随机推荐
- docker中清理冗余的image,container
1) 首先进入超级用户模式 [root@docker ~]# sudo su2) 删除container ( container运行时是不能删除的 )首先停止container [root@docke ...
- [IPSEC PKI]
PKI: 对称加密 非对称加密(混合加密) 数字签名 理论概述: (1)预备知识 对称加密:加密密钥和揭秘蜜钥是同一个密钥 缺点:不适合在互联网上传输密钥 密钥维护工作量大 n(n-1)/2 : ...
- SpringMVC中的@PathVariable
@PathVariable是用来动态获得url中的参数的,代码示例如下: 可以在代码中获得lev_1.lev_2和target参数的值看一下 // 支持跳转到WEB-INF/目录下二层目录 @Requ ...
- js 中的算法题,那些经常看到的
js中遇到的算法题不是很多,可以说基本遇不到.但面试的时候,尤其是一些大公司,总是会出这样那样的算法题,考察一个程序员的逻辑思维能力.如下: 1.回文. 回文是指把相同的词汇或句子,在下文中调换位置或 ...
- ZooKeeper学习第三期---Zookeeper命令操作
一.Zookeeper的四字命令 Zookeeper支持某些特定的四字命令字母与其的交互.他们大多数是查询命令,用来获取Zookeeper服务的当前状态及相关信息.用户在客户端可以通过telnet或n ...
- Qt——QLineEdit使用总结
QLineEdit是一个单行文本编辑控件. 使用者可以通过很多函数,输入和编辑单行文本,比如撤销.恢复.剪切.粘贴以及拖放等. 通过改变QLineEdit的 echoMode() ,可以设置其属性,比 ...
- 20135306黄韧[2.72 2.77 3.70](http://i.cnblogs.com/EditPosts.aspx?opt=1)
2.72 A.size_t是无符号整数,因此左边都会先转换为无符号整数,它肯定是大于等于0的. B.判断条件改为 if(maxbytes > 0 && maxbytes > ...
- Linux下OpenSSL的安装与使用
Linux下OpenSSL的安装与使用 OpenSSL简介 OpenSSL是一个SSL协议的开源实现,采用C语言作为开发语言,具备了跨平台的能力,支持Unix/Linux.Windows.Mac OS ...
- iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话,iTunes,iBooks )
在网上找到了下在记录下来以后方便用 在程序中调用系统自带的应用,比如我进入程序的时候,希望直接调用safar来打开一个网页,下面是一个简单的使用:
- Win7下手动卸载oracle 11G
由于安装过程中遇到的之前提到的那个问题,http://www.cnblogs.com/shenliang123/p/3141886.html 知道解决方法后,也只能将oracle重新卸载后再进行安装 ...