python - Python - 在 TCP RST 之后从套接字读取剩余数据
问题描述
我正在使用以下用例实现文件传输协议:
- 服务器在几个帧内逐块发送文件。
- 客户端可能会取消传输:为此,它会发送一条消息并在 TCP 级别断开连接。
在这种情况下,在服务器端(在 Windows 上运行的 Python)发生的情况是,我在将数据发送到客户端时捕获了 ConnectionResetException(这是正常的,客户端已断开套接字)。我想读取客户端发送的最新数据(用于中止调用的消息),但调用 mysocket.recv() 仍然会引发 ConnectionResetException。
通过wireshark 捕获,我可以清楚地看到消息在TCP 断开之前由客户端正确发送。
有什么想法吗?谢谢!
虚拟现实
解决方案
为了了解如何处理这种情况,您需要了解 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 文档没有做出这样的免责声明。
推荐阅读
- django - Django:芹菜为同一任务显示不同的状态
- python - 字典,从键调用值
- python - 如何安排 python 脚本使用 Windows 任务调度程序发送电子邮件
- python - ModuleNotFoundError:没有名为“skimage.filters._sparse_cy”的模块
- c++ - Visual Studio 2019 C++ 和 std::filesystem 更改为 ISO C++17 标准或添加 _HAS_CXX17 1 不起作用
- hibernate - org.hibernate.QueryParameterException:超出声明序数参数数量的位置
- python-3.x - python的grep、awk和sed替代品?
- javascript - 为什么 Messenger 中的消息没有按顺序发送?
- sql - 查询列在哪里显示数据库中每个表中的第一个条目?
- javascript - Firebase 实时数据库后端异步功能不更新用户