Using the recv() function in C to read from a 'stream' socket, can the len parameter be zero?
The recv() function returns zero for 'remote connection closed' and the number of bytes actually read on normal operation, so it sounds problematic if it should read zero bytes.
P.S.
Yes I know to deal with it separately, and not get to this situation, still I'm wondering if the function can handle it, I can't find any documentation about it.
RETURN VALUE Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
recv(IPC, Buffer, int n) is a blocking call, that is, if data is available it writes it to the buffer and immediately returns true, and if no data is available it waits for at least n seconds to receive any data.
If data is not available for the socket socket, and socket is in blocking mode, the recv() call blocks the caller until data arrives. If data is not available and socket is in nonblocking mode, recv() returns a -1 and sets the error code to EWOULDBLOCK.
If no error occurs, recv returns the number of bytes received and the buffer pointed to by the buf parameter will contain this data received. If the connection has been gracefully closed, the return value is zero.
The documentation for recv
on my system (Linux) says
If no messages are available at the socket, the receive calls wait for a message to arrive
and
If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.
Based on the documentation, I would expect my recv
to wait for a message, then effectively discard it (UDP) or leave it in the stream (TCP).
This could be used to test if a non-blocking TCP socket has data waiting.
Update: Testing reveals that this interpretation of the documentation is accurate.
Server:
$ perl -MIO::Socket::INET -E'
my $s = IO::Socket::INET->new(Listen => 1) or die $!;
say $s->sockport;
my $c = $s->accept or die $!;
say "[".localtime."] connected";
$c->recv(my $buf, 0) // die $!;
say "[".localtime."] received";
say <$c>;
'
39493
[Fri May 13 13:49:53 2011] connected
[Fri May 13 13:49:55 2011] received
foo
Client:
$ perl -MIO::Socket::INET -E'
my $s = IO::Socket::INET->new(
PeerAddr => "127.0.0.1",
PeerPort => $ARGV[0],
) or die $!;
sleep 2;
say $s "foo";
' 39493
(These Perl functions are just thin interfaces to the system calls. Feel free to rewrite them in C.)
I believe the answer is "it depends". If it is not specified by the standard (and indeed I believe it isn't) any implementation could do as it pleases.
EINVAL
0
and go ongcc
used to do that :)) )Actually on my implementation, it returns 0 and goes on. To check if it failed or simply returned 0, you can check errno
after the call, so it's not as problematic as you may think.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With