2013-05-03 38 views
2

我正在使用packet_mmap读取UDP数据包的快速流。当使用下列代码段,以等待数据帧正常工作。PACKET_MMAP的一些问题

// 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)) ;的声明仍然是正确了几包被读取后无限期为什么会这样呢?当系统调用发出时内核只传输帧到环形缓冲区?输入套接字被初始化为: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); 
    } 

它指出没有分组被丢弃(输出例如: “丢弃的分组:[0,5]”)。 在PACKET_RX_RING插座上的行为有所不同吗?

完整的代码此代码清单,请here

回答

2

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

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