【问题标题】:Can a non-blocking socket raise BlockingIOError from a reader/writer?非阻塞套接字可以从读取器/写入器引发 BlockingIOError 吗?
【发布时间】:2019-09-01 16:29:56
【问题描述】:

sock.recvfrom 可以向读者提出BlockingIOError 吗?比如下面

sock.setblocking(False)

def reader()
    try:
        (data, addr) = sock.recvfrom(512)
    except BlockingIOError:
        # Can this ever be raised?

loop.add_reader(sock.fileno(), reader)

同样,sock.send 可以从作家那里提出BlockingIOError 吗?

sock.setblocking(False)

def writer()
   try:
       bytes_sent = sock.send(data)
   except BlockingIOError:
       # Can this ever be raised?

loop.add_writer(sock.fileno(), writer)

我已经尝试发送/接收相当多的数据,但迄今为止从未发生过。从逻辑上讲,它永远不会真正发生吗?如果可能发生,在什么情况下?

【问题讨论】:

  • 当然,只要 EAGAIN 被引发,即您从没有缓冲数据的套接字读取,或写入没有缓冲空间的套接字。
  • @user207421 但是读取器(或写入器)不是只有在有缓冲数据(或有空间)时才会触发吗?在什么情况下可以触发读者(或作者)而不是这种情况?我是否也可以强制发生这种情况,以进行调查/测试?

标签: python linux python-3.x sockets python-asyncio


【解决方案1】:

从逻辑上讲,[BlockingIOError 在 asyncio 阅读器中] 真的不会发生吗?如果可以,在什么情况下发生?

这个问题的答案几乎肯定取决于系统。 Python 本身不提供任何保证:os.readsocket.recv 之类的函数只检查底层系统调用返回的值,如果它指示错误,则继续将系统提供的错误转换为Python 异常。

所以问题归结为如果前面的轮询/选择表明它是可读的(以及写入的等价物),从套接字读取是否会失败并出现EAGAIN 或等价物。虽然这听起来确实像是一种异常情况,但select(2) man page 明确在 BUGS 下警告它:

在 Linux 下,select() 可能会将套接字文件描述符报告为“准备读取”,但随后的读取会阻塞。例如,当数据到达但检查时校验和错误并被丢弃时,可能会发生这种情况。可能存在文件描述符被虚假报告为就绪的其他情况。因此,在不应阻塞的套接字上使用O_NONBLOCK 可能更安全。

对于非阻塞套接字,应该将“尽管如此后续读取块”读作“但后续读取失败并出现EAGAIN”,并且警告适用于此问题。该问题也不特定于select()poll(2) man page 还在其 BUGS 部分提到了虚假唤醒,有关详细信息,请参阅 select(2) 手册。

换句话说,可移植代码不应该依赖从“可读”套接字读取永远不会引发BlockingIOError。 Asyncio 不依赖它:它通过简单的not completing the futureEAGAIN 做出反应,从而重新挂起等待读取的协程。

【讨论】:

    猜你喜欢
    • 2019-05-23
    • 1970-01-01
    • 2012-07-24
    • 1970-01-01
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 2015-04-15
    相关资源
    最近更新 更多