Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recv with MSG_NONBLOCK and MSG_WAITALL

I want to use recv syscall with nonblocking flags MSG_NONBLOCK. But with this flag syscall can return before full request is satisfied. So,

  • can I add MSG_WAITALL flag? Will it be nonblocking?
  • or how should I rewrite blocking recv into the loop with nonblocking recv
like image 902
osgx Avatar asked May 31 '10 12:05

osgx


People also ask

What is Msg_waitall?

MSG_WAITALL (since Linux 2.2) This flag requests that the operation block until the full request is satisfied. However, the call may still return less data than requested if a signal is caught, an error or disconnect occurs, or the next data to be received is of a different type than that returned.

What does recv () return in C?

If successful, recv() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed. If unsuccessful, recv() returns -1 and sets errno to one of the following values: Error Code.

Is recv blocking calls?

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.

What is recv error?

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.


1 Answers

For IPv4 TCP receives on Linux at least, MSG_WAITALL is ignored if MSG_NONBLOCK is specified (or the file descriptor is set to non-blocking).

From tcp_recvmsg() in net/ipv4/tcp.c in the Linux kernel:

if (copied >= target && !sk->sk_backlog.tail)
        break;

if (copied) {
        if (sk->sk_err ||
            sk->sk_state == TCP_CLOSE ||
            (sk->sk_shutdown & RCV_SHUTDOWN) ||
            !timeo ||
            signal_pending(current))
                break;

target in this cast is set to to the requested size if MSG_DONTWAIT is specified or some smaller value (at least 1) if not. The function will complete if:

  1. Enough bytes have been copied
  2. There's a socket error
  3. The socket has been closed or shutdown
  4. timeo is 0 (socket is set to non-blocking)
  5. There's a signal pending for the process

To me this seems like it may be a bug in Linux, but either way it won't work the way you want. It looks like dec-vt100's solution will, but there is a race condition if you try to receive from the same socket in more than one process or thread.
That is, another recv() call by another thread/process could occur after your thread has performed a peek, causing your thread to block on the second recv().

like image 77
Matt Avatar answered Oct 27 '22 11:10

Matt