6

I'm trying to receive a part of a packet via recvfrom. It actually works like this:

recvfrom(sockfd, serialised_meta, 12, flags, src_addr, addrlen);
recvfrom(sockfd, serialised_buf, BUFLEN, flags, src_addr, addrlen);

The data is sent like this:

 bufd->Serialise(serialised_buf, BUFLEN+12);
 sendto(sockfd, serialised_buf, BUFLEN+12, flags, dest_addr, addrlen);

So the idea is to read some meta data first and then decide whether to receive something else. The problem is that I receive 4 '/0' bytes in the beginning if second buffer (serialised_buf). It doesn't seem to be serialisation issue, I used my serialisation before, and everything was cool, while I was receiving the whole packet (meta and data) at once. Any ideas on how it could be fixed?

PS. I understand I can just skip unnecessary bytes) But anyway, why it might be happening?

Roman
  • 1,396
  • 4
  • 15
  • 39

2 Answers2

15

UDP isn't a "stream" protocol... once you do the initial recvfrom, the remainder of the packet is discarded. The second recvfrom is awaiting the next packet...

mark
  • 5,269
  • 2
  • 21
  • 34
  • Ok, then how could my solution work at all? That's just out of curiosity). If the remainder of packet is discarded, second recvfrom should've work. Thanks, in advance! And now, I guess, the best way to get meta first is to use peek flag? – Roman Nov 09 '12 at 23:44
  • If you're talking about packet length, you can determine that by using an `ioctl` with `FIONREAD`. You could use the `MSG_PEEK` but I wouldn't bother unless your packet data is large and your meta is small... probably best to just skip the `ioctl` and peek altogether and have a max-buffer size (for your application) ready to go and just skip/discard the data. – mark Nov 10 '12 at 13:12
4

UDP operates on messages, not streams like TCP does. There is a 1-to-1 relationship between sendto() and recvfrom() when using UDP. There is no option to receive partial data in UDP, it is an all-or-nothing type of transport. You have to recvfrom() the entire BUFLEN+12 message in one go, then decide whether you are going to actually use it or not. That is just the way UDP works.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • It is really all at once or nothing? I remember reading somewhere that one should always check the return value of `recvfrom()`, compare it to the expected size and then repeatetly call `recvfrom` until all the data has been received. Unfortunately I dont remember where I read that. If this is non-sense, it would make my life a bit easier ;) – 463035818_is_not_an_ai Jan 31 '18 at 15:37
  • ... is it possible that what I described is only required for TCP, but not for UDP? I found a site where they describe something along that line for TCP (not the one that I was refering to, but more or less the same technique: http://www.binarytides.com/receive-full-data-with-recv-socket-function-in-c/) – 463035818_is_not_an_ai Jan 31 '18 at 15:59
  • 2
    @tobi303 that is what happens in TCP, not in UDP. Although the return value is indeed the number of bytes read, if the supplied buffer is too small to receive the entire message, `recvfrom` in UDP fills the buffer as much as it can, discards the remaining unread data, and reports an `EMSGSIZE` error. So you only get one chance to receive the full message. – Remy Lebeau Jan 31 '18 at 15:59
  • 1
    thanks for the reply. So it is, sloppy speaking, all or error. And in case of error I have no chance to restore the complete message. Sounds really easy :) – 463035818_is_not_an_ai Jan 31 '18 at 16:05