简体   繁体   English

非阻塞套接字上的select(),recv()和EWOULDBLOCK

[英]select(), recv() and EWOULDBLOCK on non-blocking sockets

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 非阻塞TCP套接字上的select()(RD)表示套接字已就绪
  2. following recv() would return EWOULDBLOCK despite the call to select() 以下recv()将返回EWOULDBLOCK,尽管调用select()

For recv() you would get EAGAIN rather than EWOULDBLOCK , and yes it is possible. 对于recv()你会得到EAGAIN而不是EWOULDBLOCK ,是的,这是可能的。 Since you have just checked with select() then one of two things happened: 由于您刚刚使用select()进行了检查,因此发生了以下两种情况之一:

  • Something else (another thread) has drained the input buffer between select() and recv() . 其他东西(另一个线程)已经在select()recv()之间排出了输入缓冲区。
  • A receive timeout was set on the socket and it expired without data being received. 在套接字上设置了接收超时,它在没有收到数据的情况下过期。

On Linux it's even documented that this can happen, as I read it. 在Linux上,它甚至记录了这可能发生,正如我读到的那样。

See this question: 看到这个问题:

Spurious readiness notification for Select System call 选择系统调用的虚假就绪通知

这是可能的,但只有在您有多个线程/进程试图从同一个套接字读取的情况下。

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. 我知道在流行的桌面操作中出现错误,其中O_NONBLOCK TCP套接字,特别是那些在环回接口上运行的套接字,有时在select()报告套接字准备好读取之后从recv()返回EAGAIN 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. 有关更多详细信息,请参阅我的OCaml网络应用程序环境分发版的NX库中的t_nx.ml的源代码。 ( link ) 链接

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. 未来对TCP协议的修改增加了一方“撤销”它发送的信息的能力,前提是它还没有被另一方的应用层接收。 This feature is negotiated on the connection. 此功能在连接上协商。 The other side sends you some data, you get a select hit. 另一方向你发送一些数据,你得到一个select命中。 Before you can call recv , the other side "revokes" the data using this new extension. 在您调用recv之前,另一方使用此新扩展“撤消”数据。 Your read gets a "would block" error because no data is available to be read. 您的read会出现“阻塞”错误,因为没有可读取的数据。

The select function is a status-reporting function that does not come with future guarantees. select函数是一种状态报告功能,不具备未来保证。 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. 假设select on命中现在确保后续操作不会阻塞,就像使用任何其他状态报告功能一样无效。 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. 它与使用access一样糟糕,试图确保后续操作不会因为不正确的权限而失败,或者使用statfs来确保后续写入不会因完整磁盘而失败。

Though my application is a single-threaded one, I noticed that the described behavior is not uncommon in RHEL5. 虽然我的应用程序是单线程的,但我注意到所描述的行为在RHEL5中并不罕见。 Both with TCP and UDP sockets that were set to O_NONBLOCK (the only socket option that is set). TCP和UDP套接字都设置为O_NONBLOCK(设置的唯一套接字选项)。 select() reports that the socket is ready but the following recv() returns EAGAIN. select()报告套接字已准备就绪,但以下recv()返回EAGAIN。

It is possible in a multithreaded environment where two threads are reading from the socket. 在多线程环境中,两个线程从套接字读取是可能的。 Is this a multithreaded application? 这是一个多线程应用程序吗?

If you do not call any other syscall between select() and recv() on this socket, then recv() will never return EAGAIN or EWOULDBLOCK. 如果你没有在这个套接字上调用select()和recv()之间的任何其他系统调用,那么recv()将永远不会返回EAGAIN或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(). 我不知道它们对recv-timeout意味着什么,但是,POSIX标准在这里没有提到它,所以你可以安全地调用recv()。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM