简体   繁体   中英

Can a non-blocking socket raise BlockingIOError from a reader/writer?

Can a sock.recvfrom ever raise a BlockingIOError from a reader? Such as below

sock.setblocking(False)

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

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

Similarly, can a sock.send ever raise a BlockingIOError from a writer?

sock.setblocking(False)

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

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

I've experimented by trying to send/recv a fair bit of data, but it's never happened so far. Can it never actually happen, logically? If it can happen, under what circumstances?

Can [ BlockingIOError in an asyncio reader] never actually happen, logically? If if it can happen, under what circumstances?

The answer to this question will almost certainly be system-dependent. Python itself doesn't provide any guarantees on the matter: functions like os.read and socket.recv just check the value returned by the underlying system call and, if it indicates an error, go on to convert the system-provided error to a Python exception.

So the question boils down to whether a read from a socket can fail with EAGAIN or equivalent if a preceding poll/select has indicated that it was readable (and the equivalent for writes). While that certainly sounds like an abnormal situation, the select(2) man page explicitly warns of it under BUGS:

Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.

With non-blocking sockets, one should read "nevertheless a subsequent read blocks" as "nevertheless a subsequent read fails with EAGAIN ", and the warning applies to this question. The issue is not specific to select() either; the poll(2) man page also mentions spurious wakeups in its BUGS section, referring to the select(2) manual for details.

In other words, portable code should not rely on reads from "readable" sockets never raising BlockingIOError . Asyncio doesn't rely on it: it reacts to EAGAIN by simply not completing the future , and thereby re-suspending the coroutine that awaits the read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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