我正在尝试发送和接收原始以太网帧,以将网络设备作为模拟环境中的媒体访问 Controller 。 因此,通过非阻塞语句接收数据包非常重要。
现在原始以太网帧的发送工作正常,但关于接收路径的一件事让我感到困惑: 我如何知道一帧在哪里结束而另一帧从哪里开始。
我基本上做的是打开一个原始套接字:
device.socket = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
将其设置为非阻塞:
flags = fcntl(s,F_GETFL,0);
assert(flags != -1);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
然后循环调用recv()函数从套接字中获取数据:
length = recv(s, buffer, ETH_FRAME_LEN_MY, 0);
但据我所知,recv() 函数只返回接收缓冲区中当前可用的字节数,因此我不知道是否有另一个帧开始或者我是否仍在读取“旧”数据包.
而且由于以太网帧的长度不包含在 header 中,我无法自己完成此操作。
提前致谢!
最佳答案
如果有人遇到同样的问题,这里有一个可能的解决方案:
您可以使用 libpcap 库(在 windows winpcap 中)将设备打开为捕获设备:
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
Pcap_t *handle; /* packet capture handle */
/* open capture device*/
/* max possible length, not in promiscous mode, no timeout!*/
handle = pcap_open_live(dev, 65536, 0, 0, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
}
/* set capture device to non blocking*/
if(pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf)){
fprintf("Could not set pcap interface in non blocking mode: %s \n", errbuf);
}
现在你可以循环调用pcap_dispatch函数来接收数据包了:
int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
您必须提供处理数据的回调函数。 参见 https://www.freebsd.org/cgi/man.cgi?query=pcap_dispatch&apropos=0&sektion=3&manpath=FreeBSD+11-current&format=html了解更多信息。
您可以使用注入(inject)函数发送原始以太网帧:
pcap_inject(pcap,frame,sizeof(frame));
关于c - 在原始套接字上获取以太网帧长度(非阻塞),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47513008/