NS3网络仿真(8): 实时仿真

快乐虾

http://blog.csdn.net/lights_joy/

欢迎转载,但请保留作者信息

NS3支持实时仿真,且可以将NS3模拟生成的数据包通过主机上真实的网卡发送出去,本节尝试运行NS3中自带的fd-emu-ping示例,使用NS3模拟一台设备,再通过主机上的网口ping一台网络上的真实设备。

// Allow ns-3 to ping a real host somewhere, using emulation mode
//
//   +----------------------+    
//   |          host        |
//   +----------------------+    
//   |    ns-3 simulation   |                                      
//   +----------------------+                  
//   |      ns-3 Node       |                 
//   |  +----------------+  |                 
//   |  |    ns-3 TCP    |  |              
//   |  +----------------+  |              
//   |  |    ns-3 IPv4   |  |                 
//   |  +----------------+  |                 
//   |  |   FdNetDevice  |  |                
//   |--+----------------+--+     
//   |       | eth0 |       |                
//   |       +------+       |    
//   |          |           |
//   +----------|-----------+ 
//              |
//              |         +---------+
//              .---------| GW host |--- (Internet) -----                             
//                        +---------+ 

这个模型很清楚地表达了NS3实现这个功能的层次结构。


NS3最后的实际收发包操作是由FdNetDevice这个类来完成的,其实现方式为raw socket,但在windows下,raw socket只支持ip层以上的包收发,而不支持mac层数据的收发,因此NS3的代码无法直接在windows下使用。


观察FdNetDevice完成的操作可以发现,它只需要将NS3生成的包发送出去,再将收到的包通过下面的函数扔给NS3就可以了:


FdNetDevice::ReceiveCallback (uint8_t*buf, size_t len)


因此我们引入winpcap库完成收发包的操作,放弃rawsocket方式。

首先在StartDevice时创建winpcap的接收线程:

void
FdNetDevice::StartDevice (void)
{
......

  if (m_fd < 1000)
  {
	  m_fdReader = Create<FdNetDeviceFdReader>();
	  // 22 bytes covers 14 bytes Ethernet header with possible 8 bytes LLC/SNAP
	  m_fdReader->SetBufferSize(m_mtu + 22);
	  m_fdReader->Start(m_fd, MakeCallback(&FdNetDevice::ReceiveCallback, this));
  }
  else
  {
	  // use pcap
	  pcap_t* ph = (pcap_t*)m_fd;
	  m_hPcapThread = CreateThread(NULL, 65536, PcapThread, this, 0, NULL);
  }

}

在此接收线程中循环调用pcap的接收函数:
DWORD WINAPI FdNetDevice::PcapThread(_In_  LPVOID lpParameter)
{
	FdNetDevice* pDev = (FdNetDevice*)lpParameter;
	pDev->m_bPcapRun = true;
	pcap_t* pc = (pcap_t*)pDev->m_fd;
	while (pDev->m_bPcapRun)
	{
		pcap_dispatch(pc, 1, (pcap_handler)packet_handler, (u_char*)pDev);
	}
	return 0;
}

然后在收到数据包后调用ReceiveCallback就可以了:
/* Callback function invoked by libpcap for every incoming packet */
void FdNetDevice::packet_handler(void *_param, const void *_header, const void *_pkt_data)
{
	const struct pcap_pkthdr *header = (const struct pcap_pkthdr *)_header;
	FdNetDevice* dev = (FdNetDevice*)_param;
	uint8_t* pkt = (uint8_t*)malloc(header->len);
	memcpy(pkt, _pkt_data, header->len);
	dev->ReceiveCallback(pkt, header->len);

}

当有数据包需要发送的时候,相应地改用pcap发送:
bool
FdNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
{
.....

  size_t written = 0;
  if (m_fd < 1000)
	written = cyg_write(m_fd, buffer, len);
  else
  {
	  pcap_t* ph = (pcap_t*)m_fd;
	  pcap_sendpacket(ph, buffer, len);
	  written = len;
  }
......

  return true;
}


貌似很简单的样子。


当我们在Linux下运行此示例时使用的是eth0这样的网络名称,在windows下我们需要使用一长串的名称,不过这个名称很容易用winpcap获取:


再修改一下目标机的IP,运行示例:


轻松搞定!!!









  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值