首页 > 解决方案 > Python - 在 TCP RST 之后从套接字读取剩余数据

问题描述

我正在使用以下用例实现文件传输协议:

在这种情况下,在服务器端(在 Windows 上运行的 Python)发生的情况是,我在将数据发送到客户端时捕获了 ConnectionResetException(这是正常的,客户端已断开套接字)。我想读取客户端发送的最新数据(用于中止调用的消息),但调用 mysocket.recv() 仍然会引发 ConnectionResetException。

通过wireshark 捕获,我可以清楚地看到消息在TCP 断开之前由客户端正确发送。

有什么想法吗?谢谢!

虚拟现实

标签: pythontcp

解决方案


为了了解如何处理这种情况,您需要了解 TCP 连接是如何关闭的(参见,例如this)以及套接字 API 如何与干净关闭相关(没有失败,参见this)。

您的客户端很可能会调用 close 来终止连接。这样做的问题是,套接字接收队列中可能有未读数据或从另一端很快到达的数据,您将无法再读取,这基本上是一种错误情况。为了向另一端发出无法将发送的数据传递给接收应用程序的信号,发送复位(从技术上讲,根据 RFC,“应该发送”)并且 TCP 连接异常终止。

您可能认为启用 SO_LINGER 会有所帮助(很多很多位已经溢出,所以我不会进一步详细说明),但它不会解决客户端未读取数据导致重置的问题。

客户端需要改为调用shutdown(SHUT_WR)以指示它已完成发送,然后继续调用recv(),直到它读取到 0 个字节表示另一端已完成发送。然后您可以调用close().

请注意,Python 2 套接字文档指出

根据平台,关闭连接的一半也可以关闭另一半(例如,在 Mac OS X 上,shutdown(SHUT_WR) 不允许在连接的另一端进行进一步读取)。

这对我来说听起来像是一个错误。为了解决这个问题,您必须发送您的取消消息,然后继续阅读,直到您获得 0 个字节,以便您知道服务器收到了取消消息。你可以然后close插座。

Python 3.8 文档没有做出这样的免责声明。


推荐阅读