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,运行示例:
轻松搞定!!!
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/lights_joy/article/details/47322513