Monday, April 25, 2011

socket behaviour when in blocking mode

I'm interested in the behavior of send function when using a blocking socket.

The manual specifies nothing about this case explicitly.

From my tests (and documentation) it results that when using send on a blocking socket I have 2 cases:

  • all the data is sent
  • an error is returned and nothing is sent

In lines of code (in C for example) this translate like this:

    // everything is allocated and initilized
    int socket_fd;
    char *buffer; 
    size_t buffer_len;
    ssize_t nret;

    nret = send(socket_fd, buffer, buffer_len, 0);
    if(nret < 0)
    {
          // error - nothing was sent (at least we cannot assume anything)
    }
    else
    {
          // in case of blocking socket everything is sent (buffer_len == nret)
    }

Am I right?

I'm interested about this behavior on all platforms (Windows, Linux, *nix).

From stackoverflow
  • From the man page. (http://linux.die.net/man/2/send)

    "On success, these calls return the number of characters sent. On error, -1 is returned, and errno is set appropriately. "

    You have three conditions.

    • -1 is a local error in the socket or it's binding.

    • Some number < the length: not all the bytes were sent. This is usually the case when the socket is marked non-blocking and the requested operation would block; the errno value is EAGAIN.

      You probably won't see this because you're doing blocking I/O.

      However, the other end of the socket could close the connection prematurely, which may lead to this. The errno value would probably be EPIPE.

    • Some number == the length: all the bytes were sent.

    Iulian Şerbănoiu : Now my question referring to your answer is: Is the second case you present possible when we have a BLOCKING socket? (I only see vague words there: "usually", "probably" ... ) Because if it does not, then I'm right, there are **only** 2 cases.
    S.Lott : As I said, the other end of the socket could close prematurely. You would "probably" get an EPIPE. I have not actually tested it on all operating systems to provide absolute proof. You have three cases.
  • My understanding is that a blocking send need not be atomic, see for example the Solaris send man page:

    For socket types such as SOCK_DGRAM and SOCK_RAW that require atomic messages,
    the error EMSGSIZE is returned and the message is not transmitted when it is
    too long to pass atomically through the underlying protocol. The same
    restrictions do not apply to SOCK_STREAM sockets.
    

    And also look at the EINTR error code there:

    The operation was interrupted by delivery of a signal before any data could
    be buffered to be sent.
    

    Which indicates that send can be interrupted after some data has been buffered to be sent - but in that case send would return the number of bytes that have already been buffered to be sent (instead of an EINTR error code).

    In practice I would only expect to see this behaviour for large messages (that can not be handled atomically by the operating system) on SOCK_STREAM sockets.

0 comments:

Post a Comment