Asyncio Socket Not Reading Data Sent on Socket after Working Initially

  python, python-asyncio, sockets

I’m running into a somewhat perplexing problem in my setup and I’m not sure if it’s because I’m doing something wrong with the asyncio socket primitives or there’s a deeper issue with my networking setup.

Basically, I have a server (call it sleep-server) that instantiates a long lived TCP socket connection with another server (call it beacon-server). This is done using asyncio.open_connection:

beacon_reader, beacon_writer = await asyncio.open_connection(
    beacon_server_endpoint.ip, BEACON_PORT)

The long lived connection is kicked off with an initial request/response to the beacon server. Here’s that code:

beacon_writer.write(request)
await beacon_writer.drain()

# Read the beacon server's response
try:
    beacon_response = await asyncio.wait_for(beacon_reader.read(4096), timeout=10)
except asyncio.TimeoutError as e:
    print('Timed out waiting for beacon server sleep response')
    raise SleepRequestError(e)

# Do some stuff with the response data

This works completely fine and well. After that, the application enters a flow where it periodically writes TCP data to the Beacon server on the same socket:

while True:
    data = method_that_gets_some_data()
    beacon_writer.write(data)
    await beacon_writer.drain()

This also works completely fine. The beacon server receives its data and does what it needs to do. During this stage, the beacon server does not write anything back on the socket.

It’s only when I try to receive data from the beacon server socket again that things go wrong. Basically, via a separate mechanism the beacon server is told to fetch the existing socket (the one that is currently being written to by the sleep server) and send a message down to it. For business reasons, the beacon server manages its socket connections using gevent and Python’s built in socket library, but it’s the same stuff, and based on the above flow we already know it works. Here’s the code for sending a message back down onto the socket:

# client.connection is just a python Socket object

client.connection.setblocking(0)
client.connection.send(client.wake_up_secret.decode('hex'))
print('sending client shutdown')
client.connection.shutdown(socket.SHUT_WR)

And here’s the code on the other server that receives this message:

data = beacon_reader.read()

Based on some logging I can see that the Beacon server is properly performing the send() to the socket. I also see that the sleep-server is getting to the code where it runs beacon_reader.read(). However, the sleep server just blocks there even after the Beacon server has sent down its packet. I’ve tried playing around with the size paramater in the read() command, even setting it as low as 2 just to see if I could get anything off the socket, but there’s nothing. I’ve also tried removing the connection.shutdown(), which doesn’t seem to help either.

What’s baffling is clearly it worked before since I was able to get an initial response, and clearly it’s tied to the correct socket since the beacon_writer is functioning with no problems. So I’m curious if I’m just doing something stupid with the underlying asyncio library or something.

Source: Python Questions

LEAVE A COMMENT