3

So in the case of TCP streams, one needs to keep track of how much is read of the message by each recv call. Partial reads can then be pieced together and ultimately the message can be received ok.

But for UDP messages, how should partial reads be handled (assuming that all UDP messages are small enough to avoid fragmentation)? As remaining data of partial messages seem to be discarded, is it just a matter of making sure that recvfrom returns the same size as the buffer that's been sent? If there is a difference it means it's a partial and defective message and it should be skipped.

So conceptually, while the TCP example needs a loop, the UDP example just needs an if statement.

Is this correct?

c00kiemonster
  • 22,241
  • 34
  • 95
  • 133

4 Answers4

2

It is not possible to do partial reads in UDP. UDP guarantees the datagram received is as was sent, fragmented or not, so must have received the entire datagram before you can read it.

See: http://en.wikipedia.org/wiki/User_Datagram_Protocol, you can follow the references in there for more official sources.

As for reading into a buffer you will need a buffer at least the size of any possible datagram. Or another common way is to include the size on the datagram near the beginning of the datagram so you can read only those bytes to get that number then use a buffer the appropriate size.

markmnl
  • 11,116
  • 8
  • 73
  • 109
  • 1
    `Datagrams – Packets are sent individually and are checked for integrity only if they arrive. Packets have definite boundaries which are honored upon receipt, meaning a read operation at the receiver socket will yield an entire message as it was originally sent.` So does that mean when I receive a datagram I can always be sure it has the same size and content as what was sent originally? That is, the only 'error' that can happen is when a datagram is dropped altogether? In that case, what's the point with recvfrom returning the read size? And I don't mean to be snarky, I just want to learn... – c00kiemonster Oct 21 '13 at 12:31
  • @c00kiemonster You need the length because you don't in general know what was sent. – user207421 Aug 05 '15 at 01:48
  • @c00kiemonster because the sender could send different sized datagrams - it is entirely up to the sender how many bytes their datagram is, hence I say "need a buffer at least size of any possible datagram [for your application]" - if you receive a datagram larger than the largest your application supports then its either a malicious or buggy peers so just discard it. – markmnl Aug 05 '15 at 03:11
1

Incorrect. If recv() returns the same length it was given, the message was either that length or greater. There is no way of telling which. The correct technique is to use a buffer one greater than the largest possible datagram expected. Then if you get that length, it must have been an error on the sender's part.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • "...buffer one greater than the largest possible datagram expected", that's one technique another is to use a buffer the same size as the max you expect and include in your own header the size. – markmnl Aug 05 '15 at 03:16
0

correct. However that if condition will work only if receiver knows in advance how many bytes are being sent by the sender in advance.

sukhvir
  • 5,265
  • 6
  • 41
  • 43
0

As already mentioned, closely related to this question is the need for a strategy to pass a properly sized (large enough) buffer to recv/recvmsg/recvfrom when using these with datagram protocols. For UDP, a simple and 100% reliable method is to pass a buffer of at least 65507 bytes, the maximum UDP payload size.

However, a cleaner method that I prefer is to explicitly ask recv() how many bytes the buffer needs to be. This can be accomplished thusly:

int buflen = recv(sockfd, NULL, 0, MSG_PEEK | MSG_TRUNC);
if (buflen < 0) {
    // handle error
    return;
}
uint8_t buf[buflen];
rxlen = recv(sockfd, buf, buflen, 0);
if (rxlen < 0) {
    // again, handle error
    return;
}
// Voila!  We've received our entire datagram
// without need to know the maximum datagram
// size before runtime.