I am rewriting an older server using Streams, and one of the problems I never manage to solve was the disconnection issue.
I have made this really simple server example:
import asyncio
async def handle_client(reader, writer):
address = writer.get_extra_info('peername')
print(f"Connection: {address}")
try:
while True:
data = await reader.read(1024)
if not data:
print(f"Disconnected: {address}.")
break
print(f"{address} Send: {data.decode()}")
writer.write('????n'.encode())
await writer.drain()
except Exception as e:
print(f"Something bad happened: {e}")
finally:
print(f"Closed: {address}")
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handle_client, '0.0.0.0', 5678)
async with server:
await server.serve_forever()
asyncio.run(main())
If I connect using netcat, everything works, if I close the netcat or the terminal, it knows the connection has ended. But if I disconnect my client network, it will never know that my client is offline. I know this is a lower level limitation, but I am thinking in ways to solve this.
Currently, my best approach was using a timeout for force a disconnection, like this example:
import asyncio
async def handle_client(reader, writer):
address = writer.get_extra_info('peername')
print(f"Connection: {address}")
try:
while True:
data = await asyncio.wait_for(reader.read(1024), timeout=10.0)
if not data:
print(f"Disconnected: {address}.")
break
print(f"{address} Send: {data.decode()}")
writer.write('????n'.encode())
await writer.drain()
except asyncio.TimeoutError:
print(f"Timeout: {address}")
except Exception as e:
print(f"Something bad happened: {e}")
finally:
print(f"Closed: {address}")
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handle_client, '0.0.0.0', 5678)
async with server:
await server.serve_forever()
asyncio.run(main())
This works, but I would need to fine-tune my application to fit all devices (and unfortunately, most of those devices that send me data were build in a time that you paid per byte send, so their keep alive interval is ridiculous long).
Is there a better way to know when there was a disconnection without needing to wait several minutes for a timeout?
Thank you for your attention.