Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't recv block until it receives all of the data?

Why doesn't the recv system call just block until all the data is received? Every time I have seen a recv call, it's in a while loop which just keeps on calling recv until all the data is there. Why not just have recv block in the first place?

like image 654
jasonbogd Avatar asked Jan 09 '12 03:01

jasonbogd


3 Answers

You can request that recv block until all data is received, with the MSG_WAITALL flag. However, if a signal arrives, a system call that has performed some work (ie, receiving part of the data) cannot be automatically restarted to receive the rest. As such, even with MSG_WAITALL, there are cases where the recv call may return before the buffer is full, and you must be prepared to handle these cases. Given this, many people simply choose to loop and not bother with little-known flags such as MSG_WAITALL.

As for why this is the case by default, there are a few reasons that come to mind:

  • Frequently you want to receive partial reads. For example, if you're incrementally displaying the data as it comes in, or if you're proxying it to somewhere else, or if the data is just so large you can't buffer the whole thing in memory at once. After all, if you're just immediately writing to a file, do you care that you split it across 200 writes instead of, say, 150?
  • Sometimes you don't even know how much data you need at the start. Consider the telnet protocol, which was popular around the time when the BSD sockets API was designed. You'll typically be receiving a handful of bytes at a time, there are no length fields telling you how much data to expect, and moreover you need to display that data right away. It doesn't make sense to block until you fill a buffer here. Likewise with line-oriented protocols such as SMTP or IMAP - you don't know how long the command is until you've received all of it.
  • recv is often used for datagram sockets, where it receives a single datagram, even if it's much smaller than the buffer provided. The natural extension to streaming sockets is to just return as much as you can without waiting.

But most importantly, since you need to be prepared to deal with a partial buffer anyway, it's good to force people to deal with it by default, so they turn up the bugs in their loop early - rather than having them remain hiding until a signal arrives at an unfortunate moment.

like image 99
bdonlan Avatar answered Oct 01 '22 04:10

bdonlan


In most cases, you don't know how much data is "all of the data". For example, if you're receiving data in a line-oriented protocol, a line might be 10 bytes long or 65 bytes long.

like image 30
David Schwartz Avatar answered Oct 01 '22 04:10

David Schwartz


You can change socket flags to either blocking or non-blocking. Your specific case actually has nothing to do with blocking or not blocking.

It would make no sense to make a network function behave in the way you describe by default - what if the stream never ends .. should the program never end? Prima facia, this doesn't seem like healthy default behavior.

Read http://www.scottklement.com/rpg/socktut/nonblocking.html to familiarize yourself with blocking and non-blocking IO.

like image 33
David Titarenco Avatar answered Oct 01 '22 03:10

David Titarenco