Search code examples
pythonlinuxsocketsudpnonblocking

Force a non-blocking UDP socket to raise BlockingIOError on sendto


I believe that a non-blocking UDP socket can raise a BlockingIOError on sendto. I would like to force this situation to test how my program behaves in this case.

sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
sock.setblocking(False)
sock.bind(('', 7777))
...
# Even if repeating in a loop, doesn't seem to raise a BlockingIOError
sock.sendto(b'abcde', ('1.2.3.4', 61908))

I have tried setting the outgoing buffer small by

buffer_size = 5
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, buffer_size)

But it either seems to have no impact, or results in OSError: [Errno 40] Message too long if the buffer is smaller than the data.

Is my belief wrong: can it never raise a BlockingIOError? Or if it can, how can I force it?

My aim here is to have an integration-style test: I want to actually have a real socket and make actual network calls. Mocking the socket for a unit-style test in this case would not be ideal.

The socket will only be used from a single-threaded Python asyncio program.


Solution

  • From TCP/IP Sockets in C: Practical Guide for Programmers, Michael J. Donahoo, Kenneth L. Calvert

    For UDP sockets, there are no send buffers, so send() and sendto() never return EWOULDBLOCK

    And from https://linux.die.net/man/2/sendto there is a hint as to why...

    Packets are just silently dropped when a device queue overflows.

    So in Python terms, BlockingIOError cannot be raised, at least on Linux.