【致谢】: 感谢关注NS3 Tutorial中文版的广大网友们,感谢NS3翻译小组,感谢初稿的翻译者们,感谢审稿和编辑们!!!   (详细的名单请查看博文翻译Tutorial
 
 
  声明:引用和转载相关内容,请尊重作者、翻译者和审稿者的辛勤付出,我们坚信开源的思想,我们希望自己的工作可以为更多的人提供帮助,我们不希望成为随意粘贴和任意复制的对象。
 
4  概念概述Conceptual Overview
翻译: 陈杰   刘小洋
piyajee@163.com  (百思论坛)
校稿: Xiaochuan Shen
编辑: ProbibidoAmor
4.1  关键的抽象概念(Key Abstractions
    在本节中,我们将回顾一些常用的网络术语,以及它们在ns-3的特定含义。
4.1.1 节点
在因特网术语中,任何一台连接到网络的计算设备被称为主机,亦称为终端。 ns -3是一个网络模拟器,而非一个专门的因特网模拟器,为此我们避开术语主机,因为这个词太容易让人联想到因特网和及其相关协议。因此,我们选用了一个来源于图论,在其他网络模拟器中亦广泛使用的术语:节点。
ns-3中基本计算设备被抽象为节点。节点由C++中的Node类来描述。Node类提供了用于管理仿真器中网络组件表示的各种方法。
你应该将节点设想为一台可以添加各种功能的计算机。为了使一台计算机有效地工作,我们可以给它添加应用程序,协议栈,外设卡及驱动程序等。NS3采用了与此相同的模型。
4.1.2 Application
4.1.2 应用程序
计算机软件通常可分为两大类: 系统软件和应用软件。系统软件根据计算模型配置和管理计算机中的各种资源,例如内存,处理器周期,硬盘,网络等。系统软件通常并不直接使用这些资源来完成用户任务。用户往往需要运行应用程序来完成一些特定的任务,而应用程序需要使用由系统软件控制的资源。
通常,系统软件和应用软件的界线表现为特权级的变化,而这种变化是通过操作系统的自陷功能(operating system traps)来实现的。在ns-3中并没有真正的操作系统的概念,更没有特权级别或者系统调用的概念。然而,我们有应用程序的概念。正如“现实世界”中在计算机上运行应用程序以执行各种任务一样,ns-3仿真环境中的应用程序在节点上运行来驱动模拟过程。
ns-3中,需要被仿真的用户程序被抽象为应用。应用在C++中用Application类来描述。这个类提供了管理仿真时用户层应用的各种方法。开发者应当用面向对象的方法自定义和创建新的应用。在本教程中,我们会使用Application类的实例:UdpEchoClientApplication UdpEchoServerApplication。也许你已经猜到了,这些应用程序包含了一个client/server应用来发送和回应仿真网络中的数据包。
4.1.3 信道
在现实世界中,人们可以把计算机连接到网络上。通常我们把网络中数据流流过的媒介称为信道。当你把以太网线插入到墙壁上的插孔时,你正通过信道将计算机与以太网连接。在ns-3的模拟环境中,你可以把节点连接到代表数据交换信道的对象上。在这里,基本的通信子网这一抽象概念被称为信道,在C++中用Channel类来描述。
Channel类提供了管理通信子网对象和把节点连接至它们的各种方法。信道类同样可以由开发者以面向对象的方法自定义。一个信道实例可以模拟一条简单的线缆(wire),也可以模拟一个复杂的巨型以太网交换机,甚至无线网络中充满障碍物的三维空间。
我们在本教程中将使用几个信道模型的实例,包括:CsmaChannel, PointToPointChannelWifiChannel。举例来说,CsmaChannel信道模拟了用于一个可以实现载波侦听多路访问通信子网中的媒介。这个信道具有和以太网相似的功能。
4.1.4 网络设备
以前,如果想把一台计算机连接到网络上,你就必须买一根特定的网络线缆,并在你的计算机上安装称为外设卡的硬件设备。能够实现网络功能的外接卡被称为网络接口卡(网卡)。现在大多数计算机出厂时已经配置了网卡,所以用户看不到这些的模块。
一张网卡如果缺少控制硬件的软件驱动是不能工作的。在Unix(或者Linux)系统中,外围硬件被划为设备设备通过驱动程序来控制,而网卡通过网卡驱动程序来控制。在UnixLinux系统中,网卡被称为像eth0这样的名字。
ns-3中,网络设备这一抽象概念相当于硬件设备和软件驱动的总和。NS3仿真环境中,网络设备相当于安装在节点上,使得节点通过信道和其他节点通信。像真实的计算机一样,一个节点可以通过多个网络设备同时连接到多条信道上。
网络设备由C++中的NetDevice类来描述。NetDevice类提供了管理连接其他节点和信道对象的各种方法,并且允许开发者以面向对象的方法来自定义。我们在本教程中将使用几个特定的网络设备的实例,它们分别是CsmaNetDevice, PointToPointNetDevice, WifiNetDevice。正如以太网卡被设计成在以太网中工作一样,CsmaNetDevice被设计成在csma信道中工作,而PointToPointNetDevice PointToPoint信道中工作,WifiNetNevicewifi信道中工作。
 
4.1.5 拓扑生成器
    在现实的网络中,你会发现主机已装有(或者内置)的网卡。在ns-3中你会发现节点附加了网络设备。在大型仿真网络中,你需要在节点、网络设备和信道之间部署许多连接。
既然把网络设备连接到节点、信道,配置IP地址等等事情在ns-3是很普遍是任务,那么我们干脆提供了拓扑生成器来使这个工作变得尽可能的容易。举例来说:创建一个网络设备,配置一个MAC地址,把此网络设备装载到节点上,设置节点的协议栈,以及连接网络设备到一个信道,这些事情都需要许多分立的ns-3核心操作。而当需要把许多设备连接到多点信道,在网际间将单个网络进行连接,则需要对ns-3核心进行更多更多的分立操作。我们提供了拓扑生成器来整合这些大量分立的步骤,使其成为一个简单易用的操作。很明显,这样做可以极大地方便用户。
 
4.2 第一个ns-3脚本
如果你按照前面所述下载了ns3仿真系统,你会发现在你的根目录下的“repos”的文件夹里有一份ns-3的发行版。进入那个目录,你可以看到一个如下的文件目录:
 
 
进入examples/tutorial目录。你会发现一个叫first.cc的文件。这一个脚本会在两个节点间创建一个简单的点到点的连接,并且在这两个节点之间传送一个数据包。让我们一行一行的分析一下这个脚本,下面就用你钟爱的编辑器打开first.cc吧。
4.2.1  样本
在文件中的第一行是emacs模式行。这行告诉了emacs我们在源代码中使用的预定格式(代码风格)
 /* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */
这向来是一个有点争议的主题,所以我们不妨现在就把它提出来。像许多大型的软件开发项目一样,ns-3项目采用了一套所有贡献代码必须遵守的代码风格。如果你想给ns-3贡献代码,你最终需要遵守在文件doc/codingstd.txt中说明的或者遵守在ns-3项目的网页here上显示的代码标准。
我们建议你在使用ns-3的代码的时候最好适应这个标准。所有的开发团队和贡献者带着不同程度的抱怨来做到了这一点。如果你使用emacs编辑器的话,emacs模式行会使代码格式符合规范更加容易。
Ns-3仿真器使用了GNU General Public License许可。你会在ns-3的每一个文件头看到相应的GNU法律条文。通常你会在GPL内容的上方看到一个相关机构的版权声明,而在GPL内容的下方会有相应的作者列表。
/*
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation;
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
4.2.2 模块包含
代码一般是以一系列的include声明开始的:
  #include "ns3/core-module.h"
  #include "ns3/simulator-module.h"
  #include "ns3/node-module.h"
  #include "ns3/helper-module.h"
为了帮助高层的脚本用户处理大量的系统中的include文件,我们把所有的包含文件,根据模块功能,进行了大致的分类。我们提供了一个单独的include文件,这个文件会递归加载所有会在每个模块中会被使用的include文件。我们给你提供了按大致功能分类的一组include文件,在使用时只需选择包含这几个包含文件(include文件),而非考虑复杂的依赖关系,在寻找所需要的头文件上花费不必要的时间。这不是最有效地方法但很明显让编写脚本文件容易多了。
在编译的过程中,每一个ns-3include文件被放在build目录下一个叫ns3的目录中,这样做可以避免include文件名的冲突。ns3/core-module.hsrc/core目录下的ns-3模块相对应。如果你查看ns3目录会发现大量的头文件。当你编译时,Waf会根据配置把在ns3目录下的公共的头文件放到build/debug 或者build/optimized目录下。Waf也会自动产生一个模块include文件来加载所有的公共头文件。
当然,既然你一步步遵循着这个手册走的话,你可能已经使用过如下命令:
  ./waf -d debug configure
来配置工程以完成调试工作。你可能同样使用了如下命令:
  ./waf
来编译ns-3。现在如果你进入../../build/debug/ns3 目录的话你会发现本节开头提到的四个头文件。你可以仔细看一下这些文件的内容,你会发现它们包含了在相关模块中的所有的include文件。
 
4.2.3 Ns3 Namespace
first.cc脚本的下一行是namespace的声明。
  using namespace ns3;
Ns-3工程是在一个叫做ns3C++ 命名空间中实现的。这把所有与ns3相关的声明,集中在一个与全局命名空间相区别的命名空间中。我们希望这样会给ns3与其他代码的集成带来好处。C++用“使用”语句(using)来把ns-3 namespace引入到当前的(全局的)声明域中。这个声明就是说,你不用为了使用ns-3的代码而必须在所有的ns-3代码前打上ns3:: 作用域操作符。如果你对命名空间并不熟悉,请查阅任何的C++手册并比较ns3命名空间和标准”std”命名空间的使用;通常你可以在coutstreams的讨论中看到命名空间的相关部分。
4.2.4 日志
下一句脚本如下:
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
我们认为本节是谈论Doxygen 文件系统的好地方。如果你查看ns-3项目的网站(ns-3 project),你会在导航栏中发现一个指向“Doxygen (ns-3-dev)” 的链接。打开链接,你会被带到当前开发版文档页面。同时还有一个“Doxygen (stable)”得链接,它是最新的ns-3稳定发行版的文档页面。
在左边,你能找到一个文档结构的图形化目录。在ns-3的导航树中NS-3 Modules这本是一个开始的好地方。如果你展开“Modules”目录会看到ns-3 模块文件的列表。这里的“模块”一级中的内容和上面讨论的模块include文件中的内容一一对应。Ns-3的日志子系统是核心模块(core module)的一部分,所以继续前进打开核心(Core)这个文件节点。接着展开调试(“Debugging”)节点,选择日志(Logging)页面。
 
   
 
你现在应该看一下日志模块的Doxygen文件。在页面顶上的#defines列表中你会看到NS_LOG_COMPONENT_DEFINE的条目。在你想要要深入了解之前,最好仔细看看日志模块的详细说明,这样你能够了解一下总体的流程。你可以继续下拉或者选择在collaboration diagram下的“更多”链接来达到目的。
一旦对日志模块有了整体的概念,那么请仔细看针对  NS_LOG_COMPO-NENT_DEFINE的文档。我不想把整个文件复制到这里,但是可以总结一下大致的意思,这一行声明了一个叫FirstScriptExample的日志构件,通过引用FirstScriptExample这个名字的操作,可以实现打开或者关闭控制台日志的输出。
 
4.2.5  Main Function
下面的脚本是:
    int
  main (int argc, char *argv[])
  {
这就是你的脚本程序的主函数的声明。正如任何其它C++程序一样,你需要定义一个会被第一个执行的主函数。你的ns-3脚本没有什么特别的,就和一个普通的C++程序一样。
下面两行脚本是用来使两个日志组件生效的。它们被内建在Echo Client Echo Server 应用中:
    LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
如果你已经读过了日志组件文档,你会看到日志分成一系列详尽级别。这两行代码将回显clientsserver的日志级别设为”INFO”级。这样,当仿真发生数据包发送和接受时,对应的应用就会输出相应的日志消息
关于日志模块,我们在后续内容中会详细介绍。现在我们直接着手创建拓扑和运行仿真。我们使用拓扑生成器对象来使这件事尽可能的容易。