c - 在原始套接字上获取以太网帧长度(非阻塞)

标签 c linux sockets nonblocking recv

我正在尝试发送和接收原始以太网帧,以将网络设备作为模拟环境中的媒体访问 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/

相关文章:

c++ - 从另一个进程中获取内存

c - 内存分配违规后 free() 的奇怪行为

linux - 仅当线程运行时才向线程发送信号

java - SpringBoot Java Linux

java - 如何在 Ubuntu Linux 启动时运行 Java 应用程序

c - 在 C 中添加对换行符 (\n) 的支持

ios - Obj C 调用 Cocos2dx C++ 非静态函数

linux - GhostScript:Windows 7 转换成功,而 Linux 失败

java - 对于socket来说,有没有比netty更好的框架呢?

node.js - socket.io:高流量时出现错误请求错误