如何检测asyncio.StreamWriter.write上的关闭套接字?

时间:2020-01-27 01:58:33

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

我终于开始学习python的asyncio,并正在创建一个简单的客户端服务器。我可以轻松地使用open_connectionstart_server并开始谈论一切。但是,当一侧意外关闭连接时,我遇到了一些意外行为。

在客户端,我可以很容易地检测到服务器已关闭连接,因为等待StreamReader.read的任何调用都出错或什么都不返回。但是,无论对方是否仍打开套接字,StreamWriter.write / await StreamWriter.drain调用似乎都能成功,这使我感到困惑。

客户(在通过run_until_complete调用的协程中:

_, writer = await asyncio.open_connection('127.0.0.1', 1234)
_ = input('Connected.  Type and press enter to attempt send.')

try:
    writer.write(b'A message')
    await writer.drain()
    print('Sent successfully.')

except:
    print(traceback.print_exc())
finally:
    writer.close()
    await writer.wait_closed()

服务器(同步版本,我也尝试过异步服务器):

with socket.socket() as s:
    s.bind(('0.0.0.0', 1234))
    s.listen(1)

    con, addr = s.accept()
    with con:
        print(f'Connected to {addr[0]}:{addr[1]}')
        _ = input('Type and press Enter to close.')

如果我启动服务器,连接客户端,然后让服务器终止连接,然后告诉客户端写,我希望根据文档和this StackOverflow post会收到异常,但是客户端只能打印Sent successfully.经过Python 3.7.6和Python 3.8.1测试。

我知道这在许多实际应用中都无关紧要,因为您可能会有某种读取循环,因此您可以通过调用StreamReader.read来了解该问题。这么多话,我迷茫了为什么无法检测到write上的故障?

1 个答案:

答案 0 :(得分:1)

您要实现的内容与TCP套接字的工作方式不兼容。您的drain()成功不是因为异步特性,而是因为基础的write()成功。操作系统级别的写入成功是因为它被内核缓冲以提高效率。

如果要检测到客户端仍在,则需要设计一个协议,要求该客户端对写入进行响应,并在读取该响应时检测eof。但是即使如此,您仍需要在读取时超时,因为无法保证客户端的断开连接始终是“干净的”并导致关闭信号。