ndnSIM的使用教程

目录

一、安装

二、使用

2.1 ndnSIM模拟程序

2.2 ndnSIM模拟程序目录

2.3 仿真程序分析

2.3.1 画拓扑图  

2.3.2 配路由

2.3.3 安装程序

2.3.4 写自己的APP

三、进阶


一、安装

1、建议使用ubuntu20.04桌面版安装,因为桌面版安装出来还可以看到python生成的拓扑图。

2、安装教程请求参考官方网站的安装连接。

Getting Started — ndnSIM documentation

3、下载源码的目录结构

4、判断是否安装成功,进入上图所示的ns-3目录下,运行以下命令

$ ./waf --run=ndn-simple --vis

出现如下所示的拓扑图:

点击图中的 "Simulate (F3)" 可以看到拓扑变绿色,数据正常传输,就表示安装成功了。

二、使用

2.1 ndnSIM模拟程序

    ndnSIM的模拟程序的代码逻辑一般有3部分组成。

    (1)画拓扑;

    (2)配路由;

    (3)在拓扑图中选两个节点,一个安装发包程序(consumer)用于发兴趣包,一个安装收包和发送数据包的程序(producer)。

2.2 ndnSIM模拟程序目录

    如下图所示,ndnSIM的所有仿真模拟程序都放在  ns-3/scratch 目录下,每个程序必须以 .cc 结尾。

    图中,作者自己创建了 wgh0,wgh1,wgh2,...等多个仿真程序,可以在ns-3目录下通过以下命令运行 wgh1.cc 这个仿真程序

$ ./waf --run=wgh1 --vis

    读者可以直接复制ns-3/scratch 目录下 ndn-simple.cc 文件到相同目录下的  wgh1.cc 文件, 然后使用以上命令运行 wgh1.cc 这个仿真程序,这就相当与读者自己写了个仿真程序!!!

2.3 仿真程序分析

    本节直接讲一种比较方便通用的仿真程序写法,不使用ndn-simple.cc为例,而是使用作者自己写的仿真代码为例。在scratch文件夹下创建文件wgh1.cc,写入以下内容。

#include "helper/ndn-app-helper.hpp"
#include "helper/ndn-fib-helper.hpp"
#include "helper/ndn-stack-helper.hpp"
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/ndnSIM-module.h"
#include "utils/tracers/ndn-app-delay-tracer.hpp"

namespace ns3 {

int main(int argc, char* argv[])
{
	CommandLine cmd;
	cmd.Parse(argc, argv);

	// 25 拓扑图的大小, 画拓扑图
	AnnotatedTopologyReader topologyReader("", 25);
	topologyReader.SetFileName("scratch/wgh1-tp.txt");
	topologyReader.Read();

	ndn::StackHelper ndnHelper ;
	ndnHelper.InstallAll() ;

	ndn::StrategyChoiceHelper::InstallAll("/", "/localhost/nfd/strategy/best-route");


	ndn::FibHelper ndnFibHelper ;
	Ptr<Node> node0 = Names::Find<Node>("Node0");
	Ptr<Node> node1 = Names::Find<Node>("Node1");
	Ptr<Node> node2 = Names::Find<Node>("Node2");
	Ptr<Node> node3 = Names::Find<Node>("Node3");
	Ptr<Node> node4 = Names::Find<Node>("Node4");
	Ptr<Node> node5 = Names::Find<Node>("Node5");
	Ptr<Node> node6 = Names::Find<Node>("Node6");
	Ptr<Node> node7 = Names::Find<Node>("Node7");
	Ptr<Node> node8 = Names::Find<Node>("Node8");
	// 添加路由
	std::string prefix = "/hello";
	ndnFibHelper.AddRoute(node0, prefix, node1, 25) ;
	ndnFibHelper.AddRoute(node1, prefix, node4, 25) ;
	ndnFibHelper.AddRoute(node4, prefix, node5, 25) ;
	ndnFibHelper.AddRoute(node5, prefix, node8, 25) ;

	// 选两个点安装 consumer 和  producer
	// Getting containers for the consumer/producer
	Ptr<Node> producerNode = Names::Find<Node>("Node8");
	Ptr<Node> consumerNode = Names::Find<Node>("Node0");
	ndn::AppHelper consumerHelper("Wgh0App");
	consumerHelper.Install(consumerNode);
	ndn::AppHelper producerHelper("Wgh0Pro");
	producerHelper.Install(producerNode);
	// ---------------------------------------- install app

	Simulator::Stop(Seconds(20.0));

	Simulator::Run();
	Simulator::Destroy();

	return 0;
}

} // namespace ns3

int main(int argc, char* argv[])
{
	return ns3::main(argc, argv);
}

2.3.1 画拓扑图  

  可以看到,画拓扑图的代码只有三行。

// 25 拓扑图的大小, 画拓扑图
AnnotatedTopologyReader topologyReader("", 25);
// 25 是拓扑图大小,拓扑图是画在一个正方形网格图上的,25是网络图面积,横坐标5个格,纵坐标5个格
topologyReader.SetFileName("scratch/wgh1-tp.txt");
// 读出当前目录下的画图文件“wgh1-tp.txt”
topologyReader.Read();

    我们来看看"wgh1-tp.txt"的内容,文件前半段 route 区域是设置每个路由在网格图中的位置,link区域的配置路由器之间的连接。

# topo-grid-3x3.txt

# any empty lines and lines starting with '#' symbol is ignored
#
# The file should contain exactly two sections: router and link, each starting with the corresponding keyword
#
# router section defines topology nodes and their relative positions (e.g., to use in visualizer)
router

# each line in this section represents one router and should have the following data
# node  comment     yPos    xPos
Node0   NA          3       1
Node1   NA          3       2
Node2   NA          3       3
Node3   NA          2       1
Node4   NA          2       2
Node5   NA          2       3
Node6   NA          1       1
Node7   NA          1       2
Node8   NA          1       3
# Note that `node` can be any string. It is possible to access to the node by name using Names::Find, see examples.

# link section defines point-to-point links between nodes and characteristics of these links
link

# Each line should be in the following format (only first two are required, the rest can be omitted)
# srcNode   dstNode     bandwidth   metric  delay   queue
# bandwidth: link bandwidth
# metric: routing metric
# delay:  link delay
# queue:  MaxPackets for transmission queue on the link (both directions)
Node0       Node1       1Mbps       1       10ms    10
Node0       Node3       1Mbps       1       10ms    10
Node1       Node2       1Mbps       1       10ms    10
Node1       Node4       1Mbps       1       10ms    10
Node2       Node5       1Mbps       1       10ms    10
Node3       Node4       1Mbps       1       10ms    10
Node3       Node6       1Mbps       1       10ms    10
Node4       Node5       1Mbps       1       10ms    10
Node4       Node7       1Mbps       1       10ms    10
Node5       Node8       1Mbps       1       10ms    10
Node6       Node7       1Mbps       1       10ms    10
Node7       Node8       1Mbps       1       10ms    10

    我们看看画出来是什么效果。

2.3.2 配路由


	ndn::FibHelper ndnFibHelper ;
	Ptr<Node> node0 = Names::Find<Node>("Node0");
	Ptr<Node> node1 = Names::Find<Node>("Node1");
	Ptr<Node> node2 = Names::Find<Node>("Node2");
	Ptr<Node> node3 = Names::Find<Node>("Node3");
	Ptr<Node> node4 = Names::Find<Node>("Node4");
	Ptr<Node> node5 = Names::Find<Node>("Node5");
	Ptr<Node> node6 = Names::Find<Node>("Node6");
	Ptr<Node> node7 = Names::Find<Node>("Node7");
	Ptr<Node> node8 = Names::Find<Node>("Node8");
	// 添加路由
	std::string prefix = "/hello";
	ndnFibHelper.AddRoute(node0, prefix, node1, 25) ;
    // 给node0节点添加一条路由, "/hello" 下一跳指向 node1
	ndnFibHelper.AddRoute(node1, prefix, node4, 25) ;
	ndnFibHelper.AddRoute(node4, prefix, node5, 25) ;
	ndnFibHelper.AddRoute(node5, prefix, node8, 25) ;

    也可以使用全局路由算法给整个网络配置某条最佳路由,但作者觉得那样不太灵活,所以建议这样手工配。如果需要使用全局路由算法,读者可以参考代码Examples — ndnSIM documentation

2.3.3 安装程序

	// 选两个点安装 consumer 和  producer
	// Getting containers for the consumer/producer
	Ptr<Node> producerNode = Names::Find<Node>("Node8");
	Ptr<Node> consumerNode = Names::Find<Node>("Node0");
	ndn::AppHelper consumerHelper("Wgh0App");
	consumerHelper.Install(consumerNode);
	ndn::AppHelper producerHelper("Wgh0Pro");
	producerHelper.Install(producerNode);
	// ---------------------------------------- install app

    以上4行代码的意思就是在consumerNode 这个(Node0)节点安装 Wgh0App 这个程序, 在 producerNode这个节点(Node8)安装 Wgh0Pro 这个程序。

2.3.4 写自己的APP

    Wgh0App和 Wgh0Pro ,是作者自己写的一个发兴趣包的程序和一个收兴趣包的应用程序。这两个程序放在“ns-3/src/ndnSIM/apps”目录下,如下图中的 wgh0-app.hpp, wgh0-app.cpp, wgh0-pro.hpp, wgh0-pro.cpp这4个文件。

    读者可以直接将这4个文件复制到“ns-3/src/ndnSIM/apps”目录下,就可以直接在模拟仿真程序里用了。这四个程序的代码,首先是发包程序的.hpp和.cpp代码

// wgh0-app.hpp
#ifndef WGH0_APP_H_
#define WGH0_APP_H_

#include "ns3/ndnSIM/apps/ndn-app.hpp"

namespace ns3 {

class Wgh0App : public ndn::App {
public:
  static TypeId
  GetTypeId();

  virtual void
  StartApplication();

  virtual void
  StopApplication();

  virtual void
  OnData(std::shared_ptr<const ndn::Data> contentObject);

private:
  bool m_firstTime = true;
  EventId m_sendEvent; ///< @brief EventId of pending "send packet" event
  void ScheduleNextPacket();
  void SendInterest();

};

} // namespace ns3

#endif // CUSTOM_APP_H_

      读者不用理会.hpp文件,应该什么都不用改。都用以上的模板就行了,可以改类名,改了类名就相当于改了APP名称,在仿真程序中安装时,传入的就是类名。 

// wgh0-app.cpp
#include <iostream>
#include <thread>
#include "model/ndn-common.hpp"
#include "wgh0-app.hpp"

#include "ns3/ptr.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/ndnSIM/helper/ndn-stack-helper.hpp"
#include "ns3/ndnSIM/helper/ndn-fib-helper.hpp"
#include "ns3/random-variable-stream.h"
#include "ns3/ndnSIM/ndn-cxx/lp/tags.hpp"


NS_LOG_COMPONENT_DEFINE("Wgh0App");

namespace ns3{
NS_OBJECT_ENSURE_REGISTERED(Wgh0App);

// 根据类名对下面的代码做小修改
TypeId Wgh0App::GetTypeId(){
	static TypeId tid = TypeId("Wgh0App").SetParent<ndn::App>().AddConstructor<Wgh0App>();
	return tid;
}

// 这个函数会被ns-3调用一次来启动我们写的代码,因此我们在这个函数里启动发包线程
void Wgh0App::StartApplication(){
	ndn::App::StartApplication();
    SendInterest();
}

// 不用改这个函数
void Wgh0App::StopApplication(){
	ndn::App::StopApplication();
}

// 用来控制1秒钟内发包的数量
void Wgh0App::ScheduleNextPacket()
{
  if (m_firstTime) {    // 如果是第一次启动
    m_sendEvent = Simulator::Schedule(Seconds(0.0), &Wgh0App::SendInterest, this);
    m_firstTime = false;
  }
  else if (!m_sendEvent.IsRunning())   
    m_sendEvent = Simulator::Schedule(Seconds(1.0 / 10.0), &Wgh0App::SendInterest, this);
    // 其中,以上的10.0表示1秒钟内发10个兴趣包。
}



// 发兴趣包的函数,直接在下面的基础上改改兴趣包的名称应该就满足好多需求了。
// 读者可以自己构造兴趣包,并调用 
// m_transmittedInterests(interestPtr, this, m_face);和 m_appLink->onReceiveInterest(*interestPtr); 就能把兴趣包发出去了
void Wgh0App::SendInterest(){
	static uint64_t interestId = 0 ;
	ndn::Name interestName("/hello");
	interestName.appendSequenceNumber(interestId ++) ;
	auto interestPtr = std::make_shared<ndn::Interest>(interestName);

	Ptr<UniformRandomVariable> rand = CreateObject<UniformRandomVariable>();
	interestPtr->setNonce(rand->GetValue(0, std::numeric_limits<uint32_t>::max()));

	interestPtr->setInterestLifetime(ndn::time::seconds(2));

	std::cout << "send interest : " << *interestPtr << std::endl;
	m_transmittedInterests(interestPtr, this, m_face);

	m_appLink->onReceiveInterest(*interestPtr);
    
    ScheduleNextPacket();
    // 发完一个兴趣包,再次调用这个函数,发下一个兴趣包
}

// 收到数据包的处理函数,读者可以按自己的需要修改
void Wgh0App::OnData(std::shared_ptr<const ndn::Data> data){
	std::cout << "DATA received for name " << data->getName() << std::endl;
}

}

    接下来是收兴趣包并发出数据包的代码,以下2个.hpp和.cpp文件 

// wgh0-pro.hpp
#ifndef WGH0PRO_H_
#define WGH0PRO_H_

#include "ns3/ndnSIM/apps/ndn-app.hpp"

namespace ns3 {

class Wgh0Pro : public ndn::App {
public:
  static TypeId
  GetTypeId();

  Wgh0Pro();

  // Receive all Interests but do nothing in response
  void
  OnInterest(std::shared_ptr<const ndn::Interest> interest);

protected:
  // inherited from Application base class.
  virtual void
  StartApplication();

  virtual void
  StopApplication();
};

} // namespace ns3

#endif 

     同样不会对.hpp做什么修改。

// wgh0-pro.cpp
#include "wgh0-pro.hpp"

#include "model/ndn-common.hpp"
#include "ns3/log.h"

#include "ns3/ndnSIM/helper/ndn-fib-helper.hpp"
#include <memory>
#include "ns3/ndnSIM/ndn-cxx/lp/tags.hpp"

NS_LOG_COMPONENT_DEFINE("Wgh0Pro");

namespace ns3 {

// Necessary if you are planning to use ndn::AppHelper
NS_OBJECT_ENSURE_REGISTERED(Wgh0Pro);

TypeId
Wgh0Pro::GetTypeId()
{
  static TypeId tid = TypeId("Wgh0Pro").SetParent<ndn::App>().AddConstructor<Wgh0Pro>();

  return tid;
}

Wgh0Pro::Wgh0Pro()
{
}

// 收到兴趣包的响应函数,读者可以按自己的需要返回数据包,并调用 
// m_transmittedDatas(data, this, m_face); 和 m_appLink->onReceiveData(*data);
// 把数据包发出去就行了
void Wgh0Pro::OnInterest(std::shared_ptr<const ndn::Interest> interest)
{
	ndn::App::OnInterest(interest); // forward call to perform app-level tracing
	// do nothing else (hijack interest)
	//
	std::cout << "Receive interest : " << *interest << std::endl;

	std::string content = "hello" ;
	std::shared_ptr<ndn::Data> data = std::make_shared<ndn::Data>();
	data->setName(interest->getName());
	data->setContent((const uint8_t*)content.data(), content.size()) ;

	ndn::KeyChain keyChain ;
	keyChain.sign(*data);

	m_transmittedDatas(data, this, m_face);
	m_appLink->onReceiveData(*data);

	NS_LOG_DEBUG("Do nothing for incoming interest for" << interest->getName());
}

	void
Wgh0Pro::StartApplication()
{
	App::StartApplication();

	// equivalent to setting interest filter for "/prefix" prefix
	ndn::FibHelper::AddRoute(GetNode(), "/hello", m_face, 0);
}

	void
Wgh0Pro::StopApplication()
{
	App::StopApplication();
}

} // namespace ns3

三、进阶

    如果读者读需要改NDN的源代码,直接改 ns-3/src/ndnSIM 目录下的 ndn-cxx代码和 NFD代码即可。改完后直接使用 ./waf --run=<你的仿真程序名> --vis  这个命令来运行仿真程序就可以了。

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
根据引用\[3\]中的官方教程,安装ndnSIM在Ubuntu 20.04上需要执行以下步骤: 1. 打开终端,执行以下命令安装必要的依赖项: ``` sudo apt install build-essential libsqlite3-dev libboost-all-dev libssl-dev git python3-setuptools castxml sudo apt install gir1.2-goocanvas-2.0 gir1.2-gtk-3.0 libgirepository1.0-dev python3-dev python3-gi python3-gi-cairo python3-pip python3-pygraphviz python3-pygccxml ``` 2. 安装kiwi,执行以下命令: ``` sudo pip3 install kiwi ``` 3. 创建一个名为ndnSIM的文件夹,并进入该文件夹: ``` mkdir ndnSIM cd ndnSIM ``` 4. 克隆ns-3-dev、pybindgen和ndnSIM的仓库: ``` git clone https://github.com/named-data-ndnSIM/ns-3-dev.git ns-3 git clone https://github.com/named-data-ndnSIM/pybindgen.git pybindgen git clone --recursive https://github.com/named-data-ndnSIM/ndnSIM.git ns-3/src/ndnSIM ``` 5. 进入ns-3文件夹,并执行以下命令进行配置和编译: ``` cd ns-3 ./waf configure --enable-examples ./waf ``` 这样,你就可以在Ubuntu 20.04上成功安装ndnSIM了。请注意,这些步骤是根据官方教程提供的信息编写的,确保你的系统满足所有的依赖项,并按照步骤进行操作。 #### 引用[.reference_title] - *1* [在Ubuntu安装ndnSIM](https://blog.csdn.net/qq_44001007/article/details/107575203)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [ndnSIM学习(一)——安装ndnSIM踩坑:克隆ndnSIM时git无法访问(连接超时)的解决方案](https://blog.csdn.net/MamiyaHasaki/article/details/120578299)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值