TCP套接字:当select()表示有可用数据时,read()仍然可以使用EINTR失败吗?

时间:2018-02-24 03:27:01

标签: c sockets tcp network-programming kernel

我正在使用来自TCP套接字的非阻塞select()的{​​{1}}。当read()表示有数据可供阅读时,我不确定在select()之后是否仍需要处理EINTR

2 个答案:

答案 0 :(得分:5)

是的,绝对的。 select函数是一种状态报告功能,可以在您调用select时和注意到其返回值时报告某些事件的状态。它绝对是 no 未来的保证,期限。

这是一种非常常见的误解。但是认为select确保将来的操作将提供某些特定结果是错误的,因为认为检查磁盘上有空闲空间意味着未来的写入不会失败。即使你认为有足够的可用空间,也可以允许实现在没有足够空闲空间的情况下失败。这个空间可以填补空间并尝试使用它。

select也是如此。没有规则,实现必须以某种方式记住它给你一个select的命中,并且这会影响后续读取的实现。人们多次做出这种假设,并被它咬得可怕。不要以为只是因为你无法想到任何失败的方式,这意味着它不会失败。

例如,没有规则禁止实现执行以下操作:

  1. 收到一个包。
  2. 它是有效的TCP数据,因此select返回就绪状态。此时发出的read将返回数据。
  3. 在实施之前可以确认数据,网络接口的写入队列已满。
  4. 由于实现看到由于完整队列而无法立即发送ACK,因此它只是选择丢弃该数据包并强制另一端重新发送
  5. 后续的read操作块,因为没有要读取的数据。
  6. 如果您认为某些标准禁止它,请引用该标准。 read点击后select因任何原因导致read点击select失败后失败。 select函数从不提供未来保证。

答案 1 :(得分:2)

他们我理解文档(我没有读过内核的代码,所以我可能错了),答案是:是的。

如果在内核的read操作期间发生中断(当内核将数据从套接字的缓冲区复制到用户的内存并更新套接字的状态时),操作将被取消并且read功能将返回-1errno设置为EINTR)。

套接字是非阻塞的这一事实只会最小化“窗口”,但它不会阻止这种情况发生。

另外,即使不是这种情况,我也建议你假设EINTR是可能的。只要文档没有声明EINTR错误对非阻塞文件描述符无效,对内核实现的未来更新可能会在他们认为合适时调用此错误。

另外,考虑到即使read操作对应用程序来说是原子的,内核也在处理许多内部结构(套接字的读缓冲区本身就有许多需要在内存之后更新的元素被复制了)。因此,内部结构具有锁定/同步机构。尽管套接字是非阻塞的,但仍有一段时间可以中断呼叫。