Home > NED, OMNeT++ > OMNet++ 中的 NED 语言学习(1)

OMNet++ 中的 NED 语言学习(1)

本文是对 OMNet++4.0 中的 NED 语言的学习笔记,其内容来自OMNet++ 4.0 用户手册的第三章第1,2节。

用户需要用NED语言来描述一个仿真模型。NED代表Network Description(网络描述),它让用户声明简单模块(simple modules),从而连接或重组为复合模块(compound modules),或将一些复合模块标记为networks(网络)或自包含(self-contained))的仿真模型。信道是另一个组件类型,它的实例也能使用在复合模块中。

NED的几个特性让它能在大型项目中也具有可伸缩性:

  • 分层  复杂的模块作为一个实体,可以分解为更小的模块,从而组成复合模块。
  • 基于组件  简单模块和复合模块都是可重用的。
  • 接口  接口可以在应该使用模块和信道的地方作为一个占位符(placeholder)存在,而真正的模块或信道类型则可以在网络建立的时候通过参数来决定。例如对于一个复合模型MobileHost,它包含一个拥有IMobility模块接口的mobility子模型,那么类型可以从实现了IMobility接口的RandomWalkMobility,TurtleMobility中来选择。
  • 采用了类似于Java 的package机制来减少冲突,而ned引入的NEDPATH则类似于Java的CLASSPATH,用于指定依赖关系。
  • 内部类型 在复合模块中本地使用的信道类型和模块类型可以在复合模块内部定义,这是为了减少命名空间带来的问题。
  • 元数据注解 可以通过添加属性来为模块,信道类型,参数,gates加以注解。仿真核心并不直接使用元数据,但它们能携带为多种工具添加额外的信息,运行时环境,甚至模型中的其它模块。例如,一个模块的图形化表示(图标等)或者提示符及一个参数的测量的元(milliwatt等)都通过元数据注解来指定。

注意 继承,接口,包,内部类型,元数据注解都是在4.0之后才加入的新特性。而且NED语言可以和XML进行相互转化而不会损失数据。

下面通过一个例子来学习NED语言。

本例中的网络由结点组成,每一个结点都有一个以随机间隔时间来生成数据包的应用程序,结点本身也拥有路由功能。这里假设这个应用基于数据报进行通讯,这样就不用考虑传输层。

首先用NED来描述下图所表示的网络:

图1:网络拓扑

网络拓扑

// 定义了一个名为 Network 的网络,在 NED 语言中,注释的另一个作用是能生成文档。
network Network
{
	submodules:
		node1: Node; // Node 类型在后面再定义
		node2: Node;
		node3: Node;
		...
	connections:  // 定义了结点的连接方式:双向,速度为 100Mbps
		node1.port++ <--> {datarate=100Mbps;} <--> node2.port++;
		node2.port++ <--> {datarate=100Mbps;} <--> node4.port++;
		node4.port++ <--> {datarate=100Mbps;} <--> node6.port++;
		...
}

模块的的连接点称为gates,而port++标记则为port[ ]向量添加了一个新的gate。在其它很多系统中用端口(port)来表示gates,但OMNet++用gate来减少混淆,如其它:路由器端口,TCP端口,I/O端口等等。

按照惯例,上面的代码应当放在一个名为Net6.ned的文件中,最好将NED定义放在单独的文件中并按顺序地进行命名,但这并不是强制的。

可以在NED文件中定义任意数量的网络,但用户在每次运行时须指定想要设置的网络,常用来指定网络的方法是将network选项放到配置文件(默认是omnetpp.ini)中。

[General]
network = Network

信道 

可以创建一个信道类型,它封装好数据率等信息,而且信道类型可以直接定义在网络内部,这样就不用使用全局的命名空间,改进的网络如下所示:

//  改进的网络
network Network
{
	types:
		channel C extends ned.DatarateChannel {
			datarate = 100Mbps;
		}
	submodules:
		node1: Node;
		node2: Node;
		node3: Node;
		...
	connections:
		node1.port++ <--> C <--> node2.port++;
		node2.port++ <--> C <--> node4.port++;
		node4.port++ <--> C <--> node6.port++;
		...
}

App, Routing and Queue 简单模块 

简单模块是其它复合模块的基本成份,所有模型中的行为都被封装在简单模块中,而行为是用C++语言来定义的,NED文件只声明模块的外部可见的模块(gates,参数)。本例中可以将Node定义为一个简单模块,然而它的功能是比较复杂的(包含生成流量,路由等),所以最好分为更小的模块再组成复合模块:App用于生成流量,Routing用于路由,而Queue则负责对要发送的数据包进行排队。为了显得简洁,后两个省略了方法体。

// 分别保存为App.ned,Routing.ned,Queue.ned文件。
// 根据惯例,模块的类型名首字母大写,而参数和gate的命名则是小写的。
// @-words被称为NED中的属性,使用元数据来对对象添加注解。属性可以附加到模块,参数,gates,连接,以及其它对象中。

simple App
{
	parameters:
		int destAddress;
		...
		@display("i=block/browser");
		// 称为display string,同时也定义了图标。
	gates:
		input in; // 接收数据
		output out; // 发送数据
}

simple Routing
{
	...
}
simple Queue
{
	...
}

现在可以将3个简单模块组合成为复合模块Node:

复合模块

复合模块

module Node
{
	parameters:
		@display("i=misc/node_vs,gold");
	gates:
		inout port[];
		submodules: // 声明子模块
		app: App;
		routing: Routing;
		queue[sizeof(port)]: Queue;
	connections:
		routing.localOut --> app.in;
		routing.localIn <-- app.out;

		for i=0..sizeof(port)-1 {
			routing.out[i] --> queue[i].in;
			routing.in[i] <-- queue[i].out;
			queue[i].line <--> port[i];
		}
}

复合模块和简单模块一样,可能拥有参数和gates,在这里Node模块包含一个address参数,一个未指定大小名为port的gate vector,实际的gate vector的大小将在我们从这种类型的结点创建网络时的邻居数决定,port[]的类型是inout,它允许双向的连接。 

当仿真程序开始运行时,它载入NED文件,而程序本身应当包含实现了App,Routing,Queqe这些简单模块的C++代码。同时,仿真程序也载入配置(omnetpp.ini),并决定仿真模型在哪个网络中运行,然后网络会实例化并进入仿真。

下一节将以更细节的方式来学习NED语言。

Related posts:

  1. OMNet++ 中的 NED 语言学习(3)
  2. OMNet++ 中的 NED 语言学习(2)
  3. OMNet++ 中的 NED 语言学习(4)
  4. OMNet++ 10 分钟教程
Categories: NED, OMNeT++ Tags:
  1. No comments yet.
  1. No trackbacks yet.