2010-03-30 47 views
7

在Linux上使用UNIX套接字API,有什么方法可以保证我读取一个UDP数据包,并且只有一个UDP数据包?我正在使用recvmsg从非阻塞套接字读取数据包,其缓冲区大小比内部网络的MTU稍大。这应该确保我总是可以收到完整的UDP数据包,但是我不确定如果数据包很小,我不能保证每次recvmsg呼叫都不会收到多个数据包。我可以从套接字中读取一个UDP数据包吗?

recvmsg手册页引用MSG_WAITALL选项,该选项尝试等待,直到填充缓冲区。我们没有使用这个,那么这意味着recvmsg将在读取一个数据报后总是返回?有什么方法可以保证这一点?

理想情况下,我想要一个跨UNIX解决方案,但如果不存在,那么Linux是否有特定的解决方案?

+1

MSG_WAITALL面向流的套接字:http://linux.die.net/man/3/recvmsg正如已经回答的那样,recv/send()使用整个数据报工作,用于面向数据报的套接字。 – Ioan 2010-03-30 19:57:44

回答

12

recvmsg会返回给你一个数据包,它将是整个数据包(只要你提供的缓冲区足够大)。

the POSIX documentation

的recvmsg()函数将接收来自连接模式或连接模式的插座的消息。

“消息”是指恰好一个消息(或数据包),并且,

对于基于消息的插座,如SOCK_DGRAM和SOCK_SEQPACKET,整个消息必须在单个操作中被读取。

+0

如果有碎片。只有在整个数据包重建后,'''recievemsg'''才会返回数据? – Artium 2016-12-27 20:48:40

+0

Artium:是的,这是由操作系统执行的,用户空间只会看到组合的数据包而不是碎片。这意味着接收到的碎片数据包将被操作系统保留一段时间,等待其余的碎片。 – 2017-01-05 12:48:42

0

一个选项(我说选项)是使用使用libpcap的pcap_next并拆开它来看它是否是udp数据包。你可以这样做:

/* jump pass the ethernet header */ 
ipdata = (struct ip*)(packet + sizeof(struct ether_header)); 
length -= sizeof(struct ether_header); 

(从tcpdump的借用)

,然后测试的IP结构,看它是否是一个UDP数据包做:

if (ipdata->ip_p == IPPROTO_UDP) 

如果失败,保持循环(调用pcap_next),直到你得到你的udp包。当然,这种方法提取udp数据报更加困难,但它确实可以让你很好地进入数据包内部。请参阅tcpdump源文件以了解如何去除信息并发布。

相关问题