简体   繁体   English

如何在C中读取可变长度的UDP数据包

[英]How to read UDP packet with variable length in C

I'm sending a C struct over UDP 我正在通过UDP发送一个C结构

struct packet{
    int numInt;
    int* intList; //malloc'ed as (sizeof(int)*numInt)
}

It will be serialized as [numInt][intList[0]]...[intList[numInt-1]] . 它将被序列化为[numInt][intList[0]]...[intList[numInt-1]]

My understanding is that calling recvfrom on UDP will read the entire packet, even if the buffer doesn't hold that many bytes. 我的理解是,在UDP上调用recvfrom将读取整个数据包,即使缓冲区不包含那么多字节。 Is using a really large buffer the only option I have? 使用一个非常大的缓冲区是我唯一的选择吗?

You could pass MSG_PEEK to recvfrom to find out exactly how big the buffer needs to be. 您可以将MSG_PEEK传递给recvfrom以确切了解缓冲区需要的大小。 So just recvfrom a few bytes with MSG_PEEK to find numInt and then recvfrom the real thing (this time without MSG_PEEK ). 所以只要recvfrom有几个字节MSG_PEEK找到numInt然后recvfrom真实的东西(这次没有MSG_PEEK )。

The standard says something about MSG_PEEK , but kernel.org spells it better: 该标准说明了MSG_PEEK ,但kernel.org更好地说明了这一点:

MSG_PEEK

This flag causes the receive operation to return data from the beginning of the receive queue without removing that data from the queue. 此标志使接收操作从接收队列的开头返回数据,而不从队列中删除该数据。 Thus, a subsequent receive call will return the same data. 因此,后续的接收呼叫将返回相同的数据。

Obviously at some point you will start wondering if doubling the number of system calls to save memory is worth it. 显然,在某些时候你会开始想知道将系统调用数量加倍以节省内存是否值得。 I think it isn't. 我认为不是。

UDP packets are sent and received as a whole. UDP数据包作为一个整体发送和接收。 if you receive it, the size is right. 如果你收到它,大小是正确的。 The only thing you have to do is to supply a big enough buffer on read() or recv() or recfrom(). 你唯一要做的就是在read()或recv()或recfrom()上提供足够大的缓冲区。 The length field inside the payload is redundant, since the read() will tell you the correct size. 有效负载内的长度字段是多余的,因为read()将告诉您正确的大小。 It is also dangerous, since it relies on the sender and reciever having the same byte order. 它也很危险,因为它依赖于具有相同字节顺序的发送方和接收方。

You could try using a small buffer, just large enough to get numInt , with the MSG_PEEK flag set. 您可以尝试使用一个小的缓冲区,只要设置了MSG_PEEK标志就足够大,以获得numInt Then you can find out the size you actually need, and receive again without MSG_PEEK to get the whole thing. 然后你可以找到你真正需要的大小,并在没有MSG_PEEK情况下再次接收以获得整个事情。

I'm pretty sure recvfrom will read up to as many bytes as is told to it by its 3rd argument, len. 我很确定recvfrom会读取第三个参数len告诉它的字节数。 If there are fewer bytes available, it will return what is there. 如果有更少的可用字节,它将返回那里的内容。 If there are more, it will return up to len bytes. 如果还有更多,它将返回len个字节。 You may have to make additional calls to obtain all the data your are expecting. 您可能需要进行其他调用才能获得所需的所有数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM