gpt4 book ai didi

ethernet - libpcap 没有实时接收,似乎正在缓冲数据包

转载 作者:行者123 更新时间:2023-12-04 03:33:52 28 4
gpt4 key购买 nike

所以我正在使用需要发送和接收原始以太网帧的设备。它是一种 radio ,它使用以太网向其主机发送状态消息。它使用的协议(protocol)实际上是 IPX,但我认为使用 libpcap 发送原始以太网帧比挖掘实现 IPX 的几十年前的代码更容易(它被 TCP/IP 取代,所以它已经很老了)。

我的程序发送了一个请求包(这个包每次都完全一样,它是无状态的),设备返回一个包含我需要的数据的响应包。我正在使用 pcap_inject 在另一个线程中发送帧和 pcap_loop 来进行接收。我最初将它放在一个线程中,但尝试了 2 个线程以查看它是否解决了我遇到的问题。

问题是 libpcap 似乎没有实时接收数据包。它似乎缓冲了大约 5 个,然后一次处理它们。我希望能够以最快的速度阅读它们。有什么方法可以在 libpcap 上禁用这种缓冲,或者提高刷新率?

一些示例输出(我刚刚打印出接收数据包的时间)。注意每组之间有大约一秒钟的时间

Time: 1365792602.805750 
Time: 1365792602.805791
Time: 1365792602.805806
Time: 1365792602.805816
Time: 1365792602.805825
Time: 1365792602.805834

Time: 1365792603.806886
Time: 1365792603.806925
Time: 1365792603.806936
Time: 1365792603.806944
Time: 1365792603.806952

Time: 1365792604.808007
Time: 1365792604.808044
Time: 1365792604.808055
Time: 1365792604.808063
Time: 1365792604.808071

Time: 1365792605.809158
Time: 1365792605.809194
Time: 1365792605.809204
Time: 1365792605.809214
Time: 1365792605.809223

这是注入(inject)代码:
char errbuf[PCAP_ERRBUF_SIZE];
char *dev="en0";
if(dev==NULL){
fprintf(stderr,"Pcap error: %s\n",errbuf);
return 2;
}

printf("Device: %s\n",dev);

pcap_t *handle;
handle=pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
if(handle==NULL){
fprintf(stderr, "Device open error: %s\n",errbuf);
return 2;
}

//Construct the packet that will get sent to the radio
struct ether_header header;
header.ether_type=htons(0x0170);
int i;
for(i=0;i<6;i++){
header.ether_dhost[i]=radio_ether_address[i];
header.ether_shost[i]=my_ether_address[i];
}

unsigned char frame[sizeof(struct ether_header)+sizeof(radio_request_packet)];
memcpy(frame, &header, sizeof(struct ether_header));
memcpy(frame+sizeof(struct ether_header), radio_request_packet, sizeof(radio_request_packet));
if(pcap_inject(handle, frame, sizeof(frame))==-1){
pcap_perror(handle, errbuf);
fprintf(stderr, "Couldn't send frame: %s\n",errbuf);
return 2;
}

bpf_u_int32 mask;
bpf_u_int32 net;
if(pcap_lookupnet(dev,&net,&mask,errbuf)==-1){
pcap_perror(handle, errbuf);
fprintf(stderr,"Net mask error: %s\n",errbuf);
return 2;
}

char *filter="ether src 00:30:30:01:b1:35";
struct bpf_program fp;
if(pcap_compile(handle, &fp, filter, 0, net)==-1){
pcap_perror(handle, errbuf);
fprintf(stderr,"Filter error: %s\n",errbuf);
return 2;
}

if(pcap_setfilter(handle, &fp)==-1){
pcap_perror(handle, errbuf);
fprintf(stderr, "Install filter error: %s\n",errbuf);
return 2;
}

printf("Starting capture\n");
pthread_t recvThread;
pthread_create(&recvThread, NULL, (void *(*)(void *))thread_helper, handle);

while(1){
if(pcap_inject(handle, frame, sizeof(frame))==-1){
pcap_perror(handle, errbuf);
fprintf(stderr, "Couldn't inject frame: %s\n",errbuf);
return 2;
}
usleep(200000);
}

pcap_close(handle);
return 0;

和接收代码:
void got_packet(u_char *args,const struct pcap_pkthdr * header,const u_char * packet){
struct timeval tv;
gettimeofday(&tv, NULL);
double seconds=(double)tv.tv_sec + ((double)tv.tv_usec)/1000000.0;
printf("Time: %.6f\n",seconds);
}


void *thread_helper(pcap_t *handle){
pcap_loop(handle, -1, got_packet, NULL);
return NULL;
}

最佳答案

Is there some way to disable this buffering on libpcap



目前没有 libpcap API 可以做到这一点。

但是,根据您正在运行的操作系统,可能有针对该特定操作系统的方法,即您可以这样做,但以非可移植方式。

对于使用 BPF 的系统,包括 *BSD 和...

...OS X,鉴于 "en0" ,我怀疑您正在使用它,这样做的方法是执行以下操作:

创建一个 set_immediate_mode.h 头文件,其中包含:
extern int set_immediate_mode(int fd);

创建一个 set_immediate_mode.c 源文件,其中包含:
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <net/bpf.h>

#include "set_immediate_mode.h"

int
set_immediate_mode(int fd)
{
int on = 1;

return ioctl(fd, BIOCIMMEDIATE, &on);
}

#include <string.h>#include <errno.h> 添加到您的程序中(如果尚未包含这些文件),将 #include "set_immediate_mode.h" 添加到您的程序中,并在 pcap_open_live() 调用成功后添加以下代码:
int fd;
fd = pcap_fileno(handle);
if (fd == -1) {
fprintf(stderr, "Can't get file descriptor for pcap_t (this should not happen)\n");
return 2;
}
if (set_immediate_mode(fd) == -1) {
fprintf(stderr, "BIOCIMMEDIATE failed: %s\n", strerror(errno));
return 2;
}

这将完全禁用 BPF 通常执行的缓冲(这是您在 libpcap 中看到的缓冲;请参阅 BPF(4) 手册页),以便数据包一到达就被传递。这改变了缓冲完成的方式,可能导致 BPF 的内部缓冲区比正常缓冲完成时更快地填满,因此可能会导致数据包丢失,否则它们不会丢失,但使用 pcap_set_buffer_size() ,正如 Kiran Bandla 所建议的那样,如果它发生(它可能不会,特别是考虑到您使用过滤器来防止“无趣”的数据包首先被放入 BPF 的缓冲区),可能会有所帮助。

在 Linux 上,这目前是没有必要的 - 完成的缓冲对于数据包的传递没有超时。在 Solaris 上,它会在 Solaris 11 上类似地完成(因为 libpcap 使用 BPF),但在早期版本的 Solaris 上会有所不同(因为它们没有 BPF 而 libpcap 使用 DLPI)。在带有 WinPcap 的 Windows 上, pcap_open() 有一个标志。

future 版本的 libpcap 可能会为此提供 API;我不能保证什么时候会发生。

关于ethernet - libpcap 没有实时接收,似乎正在缓冲数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15979033/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com