select(), recv() and EWOULDBLOCK on non-blocking sockets
Asked Answered
H

8

10

I would like to know if the following scenario is real?!

  1. select() (RD) on non-blocking TCP socket says that the socket is ready
  2. following recv() would return EWOULDBLOCK despite the call to select()
High answered 26/5, 2009 at 16:25 Comment(0)
S
3

I am aware of an error in a popular desktop operating where O_NONBLOCK TCP sockets, particularly those running over the loopback interface, can sometimes return EAGAIN from recv() after select() reports the socket is ready for reading. In my case, this happens after the other side half-closes the sending stream.

For more details, see the source code for t_nx.ml in the NX library of my OCaml Network Application Environment distribution. (link)

Sills answered 26/5, 2009 at 22:52 Comment(0)
C
6

For recv() you would get EAGAIN rather than EWOULDBLOCK, and yes it is possible. Since you have just checked with select() then one of two things happened:

  • Something else (another thread) has drained the input buffer between select() and recv().
  • A receive timeout was set on the socket and it expired without data being received.
Cytosine answered 26/5, 2009 at 16:32 Comment(4)
In case of timeout, select() returns 0 so I am not worried about it.High
#define EWOULDBLOCK EAGAIN /* Operation would block */ -- found on many OSesOvation
The POSIX.1-2001 allows either errors to be returned when reading on a non-blocking socket (and doesn't require that they have the same value.)Albatross
It's funny that it is defined on many OSes to be the same error code, meaning you can't put it into a switch block for portability.Sorority
L
4

It's possible, but only in a situation where you have multiple threads/processes trying to read from the same socket.

Levkas answered 26/5, 2009 at 16:28 Comment(1)
Glad to hear that. My application is single threaded so I am fine.High
R
4

On Linux it's even documented that this can happen, as I read it.

See this question:

Spurious readiness notification for Select System call

Rogerrogerio answered 23/8, 2009 at 11:23 Comment(0)
S
3

I am aware of an error in a popular desktop operating where O_NONBLOCK TCP sockets, particularly those running over the loopback interface, can sometimes return EAGAIN from recv() after select() reports the socket is ready for reading. In my case, this happens after the other side half-closes the sending stream.

For more details, see the source code for t_nx.ml in the NX library of my OCaml Network Application Environment distribution. (link)

Sills answered 26/5, 2009 at 22:52 Comment(0)
H
1

Though my application is a single-threaded one, I noticed that the described behavior is not uncommon in RHEL5. Both with TCP and UDP sockets that were set to O_NONBLOCK (the only socket option that is set). select() reports that the socket is ready but the following recv() returns EAGAIN.

High answered 27/5, 2009 at 11:40 Comment(0)
D
1

Yes, it's real. Here's one way it can happen:

A future modification to the TCP protocol adds the ability for one side to "revoke" information it sent provided it hasn't been received yet by the other side's application layer. This feature is negotiated on the connection. The other side sends you some data, you get a select hit. Before you can call recv, the other side "revokes" the data using this new extension. Your read gets a "would block" error because no data is available to be read.

The select function is a status-reporting function that does not come with future guarantees. Assuming that a hit on select now assures that a subsequent operation won't block is as invalid as using any other status-reporting function this way. It's as bad as using access to try to ensure a subsequent operation won't fail due to incorrect permissions or using statfs to try to ensure a subsequent write won't fail due to a full disk.

Devito answered 21/2, 2019 at 1:54 Comment(0)
S
0

It is possible in a multithreaded environment where two threads are reading from the socket. Is this a multithreaded application?

Scheld answered 26/5, 2009 at 16:33 Comment(3)
Even if there's a timeout on the socket rather than just a parameter to select()? What if the timeout happens between select() and recv()?Cytosine
In this case you should not see this behaviour.Scheld
What do you mean by saying "timeout on the socket"?High
M
-1

If you do not call any other syscall between select() and recv() on this socket, then recv() will never return EAGAIN or EWOULDBLOCK.

I don't know what they mean with recv-timeout, however, the POSIX standard does not mention it here so you can be safe calling recv().

Misshape answered 26/5, 2009 at 17:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.