非阻塞套接字可以从读取器/写入器中引发BlockingIOError吗?

时间:2019-04-11 06:04:08

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

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)

我已经尝试通过发送/接收大量数据进行实验,但到目前为止从未发生过。从逻辑上说,它不可能真正发生吗?如果可以发生,在什么情况下?

1 个答案:

答案 0 :(得分:1)

  

从逻辑上讲,[a BlockingIOError在异步阅读器中永远不会真正发生吗?如果可以发生,在什么情况下?

几乎可以肯定,这个问题的答案取决于系统。 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做出反应,从而将等待读取的协程重新悬浮。