Recv with MSG_NONBLOCK and MSG_WAITALL

I want to use syscall recv with non-blocking MSG_NONBLOCK flags. But with this flag, syscall may return before a full request is made. So,

  • Can I add the MSG_WAITALL flag? Will it be non-blocking?
  • or how can I rewrite recv lock into a loop with unblocked recv
+7
linux nonblocking sockets network-programming
source share
3 answers

This is what I did for the same problem, but I would like it to confirm that it works as expected ...

 ssize_t recv_allOrNothing(int socket_id, void *buffer, size_t buffer_len, bool block = false) { if(!block) { ssize_t bytes_received = recv(socket_id, buffer, buffer_len, MSG_DONTWAIT | MSG_PEEK); if (bytes_received == -1) return -1; if ((size_t)bytes_received != buffer_len) return 0; } return recv(socket_id, buffer, buffer_len, MSG_WAITALL); } 
+4
source share

EDIT:

Plain recv () will return everything in the tcp buffer during the call, up to the requested number of bytes. MSG_DONTWAIT simply avoids blocking if there is no data ready to be read on the socket. MSG_WAITALL requests a lock until the entire number of requested bytes has been read. This way you wonโ€™t get all-or-nothing behavior. In the best case, you should get EAGAIN if the data is missing and blocked until a full message is available.

You may be able to release something from MSG_PEEK or ioctl () using FIONREAD (if your system supports it), which behaves the way you want, but I donโ€™t know how you can achieve your goal simply by using flags recv ().

+3
source share

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

From tcp_recvmsg () to 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; 
purpose

for this cast is set for the requested size if MSG_DONTWAIT is specified or some lower value (at least 1) if not. The function will end if:

  • A sufficient number of bytes have been copied.
  • Socket error
  • The socket was closed or turned off
  • timeo is 0 (socket is set to non-blocking)
  • Signal Awaiting Process

It seems to me that this may be a bug in Linux, but in any case, it will not work the way you want. It looks like the dec-vt100 solution will be, but there is a race condition if you are trying to get from the same socket in several processes or threads.
That is, another call to recv () by another thread / process may occur after your thread has done a peek, causing your thread to block the second recv ().

+2
source share

All Articles