socketssendrecv

Why is there no flag like MSG_WAITALL for send?


The flag MSG_WAITALL can be used for recv, which requests recv to block until the full request is satisfied. That means recv will not return until as much data as requested (specified by the argument len) has been received, unless an error occurs or the connection has been closed.

Why doesn't such a flag apply to send too? I think it would be very useful for sending (send doesn't return until ALL the bytes the caller wants to send has been handed to TCP send buffer)


Solution

  • user207421 is correct, but just to elaborate:

    Blocking send() (or write()) already blocks until all data has been written, it only returns early if no more data can be written, an error occurs, or a signal has been caught, i.e. the same conditions that can cause a blocking recv() with MSG_WAITALL to return early.

    Until recently I also thought a blocking write would behave essentially like a poll() for POLLOUT followed by a non-blocking write (but without the race conditions), but it really doesn't.

    If you don't believe me, look e.g. at unix_stream_sendmsg() in the linux kernel (which implements write/send* for AF_UNIX streams): whether or not it will block in its sock_alloc_send_pskb() call depends solely on the MSG_DONTWAIT flag (which is implicitly set for non-blocking sockets). It does not depend on sent != 0, which is what would be needed for non-waitall behaviour.

    For comparison, on the read side unix_stream_read_generic() will avoid blocking if copied >= target or !timeo, where

    The code for TCP is more complicated but its recvmsg also uses target and timeo as described above while its sendmsg only uses timeo (0 if MSG_DONTWAIT, otherwise SO_SNDTIMEO).

    I'm not sure what the reason is for this inconsistency between read and write, but presumably it's just a historical mistake that can't be fixed due to backwards compatibility.