3

I have simple TCP server that runs with non-blocking sockets.

Quote from manpage of recv;

When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).

The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.

When socket is readable I read it with this code:

uint8_t buf[2048];
ssize_t rlen;
while(1){
    rlen = recv(fd, buf, sizeof(buf), 0);
    if(rlen < 0){
        /* some error came, let's close socket... */
    }
    else if(rlen == 0){
        /* is there no bytes to read? do we need break; in here? */
        /* is socket closed by peer? do we need to close socket? */
    }
    /* some code that process buf and rlen... */
}

How we can know which case happens when recv returns 0?

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39

1 Answers1

3

When recv returns 0 it means that the socket has been gracefully closed by the other peer and can be closed from your side as well. When no data is present in socket, -1 is returned and errno is set to EAGAIN / ETIMEDOUT and the socket hasn't to be closed.

Finally, when -1 is returned and errno is set to a value different from EWOULDBLOCKor EAGAIN the socket has to be closed, because some unrecoverable error occurred.
For non-blocking sockets it means that no data is immediately available when recv is called. For blocking sockets) it means tgat no data is available even after the timeout (SO_RCVTIMEO) previously set with setsockopt() expired.


As you correctly quoted in your last edit, 0 can be returned from recv also if the requested size is 0.

How we can know which case happens when recv returns 0?

Just test the provided recv size (in this case it is the size of a constant array, so it doesn't make much sense; but in case it is a variable coming from elsewhere...):

bufSize = sizeof(buf);

/* further code that, who knows, might affect bufSize */

rlen = read(fd, buf, bufSize);
if(rlen < 0){
    if (errno != ETIMEDOUT && errno != EWOLUDBLOCK)
    {
        /* some error came, let's close socket... */
    }
}
else if(rlen == 0){
     if (bufSize != 0)
    {
        /* Close socket */
    }
}
Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • Isn't errno `ETIMEDOUT` means we need to close socket too? I suppose `EWOULDBLOCK` means `there is no any data right now except recv with blocking` – fakwjdkawjdawk Aug 22 '20 at 08:54
  • @fakwjdkawjdawk You are right. I wrongly had in mind a proprietary implementation I worked with, that used to return ETIMEDOUT in a blocking socket in case the timeout (`SO_RCVTIMEO`) previously set with `setsockopt ()` expired. I'll edit my answer – Roberto Caboni Aug 22 '20 at 09:23
  • by the way you forgot to change code part in your answer – fakwjdkawjdawk Aug 22 '20 at 09:56
  • `sizeof` never returns 0. – rici Aug 22 '20 at 10:07
  • 1
    @rici it's just example. also it's possible to get sizeof 0 with zero length array extension. gcc supports it; `int a[0]; printf("%u\n", sizeof(a));` – fakwjdkawjdawk Aug 22 '20 at 10:17