PACKET_MMAP的一些问题

时间:2013-05-03 12:38:48

标签: linux network-programming udp

我正在使用packet_mmap来读取快速的UDP数据包流。使用以下任一代码段等待传入帧时,它可以正常工作:

// ring[i].iov_base points to the start address of the ith frame
struct tpacket_hdr *header = (struct tpacket_hdr *) ring[i].iov_base;

// Using poll on socket to wait for data
while(!(header -> tp_status & TP_STATUS_USER))
    {
        struct pollfd pfd;
        pfd.fd      = _socket;
        pfd.events  = POLLIN | POLLERR;
        pfd.revents = 0;
        poll(&pfd, 1, -1);
    }

// Using nanosleep to wait for incoming data
while(!(header -> tp_status & TP_STATUS_USER))
    {
        struct timespec t, r;
        t.tv_nsec = 1;
        t.tv_sec = 0; 
        nanosleep(&t, &r)
    }

然而,当我尝试忙等待时(while(!(header -> tp_status & TP_STATUS_USER)) ;,在读取几个数据包后,语句无限期地保持为True。为什么会这样?内核是否仅在发出系统调用时将帧传输到环形缓冲区?输入套接字初始化为:socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))

此外,当使用此代码(使用poll或nanosleep)时,它似乎丢弃数据包,而使用UDP套接字的简单接收代码则不会,使packet_mmap实现更慢。有时,套接字会检测到丢弃的数据包,但使用PACKET_STATISTICS选项getsockopt时:

    if (header -> tp_status & TP_STATUS_LOSING)
    {
        struct tpacket_stats stats;
        socklen_t size_sock = sizeof(tpacket_stats);
        if (getsockopt(_socket, SOL_PACKET, PACKET_STATISTICS, &stats, &size_sock) > -1)
            printf("Dropped packets: [%d, %d]\n", stats.tp_drops, stats.tp_packets);
    }

它声明没有丢弃数据包(输出示例:“Dropped packets:[0,5]”)。 PACKET_STATISTICS套接字PACKET_RX_RING的行为是否有所不同?

此代码的完整代码列表可用here

1 个答案:

答案 0 :(得分:2)

万一有人遇到这个问题,忙碌的等待是“挂起”,因为tpacket_hdr正在被优化并进入寄存器并且它的值没有在内存中检查。将其标记为volatile可确保应用程序可以看到内核对此结构所做的任何更改。

使用PACKET_STATISTICS检测到的丢包是针对正在接收的前几个数据包,其余的是由于应用程序无法跟上传入的数据包,因为系统调用导致了额外的开销。