Search code examples
c++csocketstimeoutberkeley-sockets

About recv and the read buffer - C Berkeley Sockets


I am using berkeley sockets and TCP (SOCK_STREAM sockets).

The process is:

  1. I connect to a remote address.
  2. I send a message to it.
  3. I receive a message from it.

Imagine I am using the following buffer:

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);

Questions are:

  • How can I know if after calling recv first time the read buffer is empty or not? If it's not empty I would have to call recv again, but if I do that when it's empty I would have it blocking for much time.
  • How can I know how many bytes I have readed into recv_buffer? I can't use strlen because the message I receive can contain null bytes.

Thanks.


Solution

  • How can I know if after calling recv first time the read buffer is empty or not? If it's not empty I would have to call recv again, but if I do that when it's empty I would have it blocking for much time.

    You can use the select or poll system calls along with your socket descriptor to tell if there is data waiting to be read from the socket.

    However, usually there should be an agreed-upon protocol that both sender and receiver follow, so that both parties know how much data is to be transferred. For example, perhaps the sender first sends a 2-byte integer indicating the number of bytes it will send. The receiver then first reads this 2-byte integer, so that it knows how many more bytes to read from the socket.

    Regardless, as Tony pointed out below, a robust application should use a combination of length-information in the header, combined with polling the socket for additional data before each call to recv, (or using a non-blocking socket). This will prevent your application from blocking in the event that, for example, you know (from the header) that there should still be 100 bytes remaining to read, but the peer fails to send the data for whatever reason (perhaps the peer computer was unexpectedly shut off), thus causing your recv call to block.

    How can I know how many bytes I have readed into recv_buffer? I can't use strlen because the message I receive can contain null bytes.

    The recv system call will return the number of bytes read, or -1 if an error occurred.

    From the man page for recv(2):

    [recv] returns the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown.