python - Python 3.8 TLSv1.3 套接字关闭导致 ConnectionResetError 或 ConnectionAbortedError
问题描述
客户端:
data = b'\xff' * 1000000
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
#context is created by ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
ssock = context.wrap_socket(ssock, server_hostname='xd1337sv')
ssock.connect((SERVERADDR, SERVERPORT))
ssock.sendall(data)
#time.sleep(3)
ssock.close()
如果我只使用常规的非 SSL 套接字,那么在服务器接收准确数据量的情况下一切正常。如果我使用 TLS 套接字,则行为取决于版本。
如果我在 Python 3.6 上运行服务器或客户端,因此将使用 TLSv1.2,则没有问题。只有在使用 TLSv1.3 时才会出现问题,并且取决于data
客户端ssocket.close()
行的大小和执行速度。
如果我根据数据的大小放入适量的time.sleep
之前ssocket.close()
,那么我不会出错。否则,服务器将ConnectionResetError [WinError 10054] An existing connection was forcibly closed by the remote host
只获取和接收部分数据,或者抛出ConnectionAbortedError [WinError 10053] An established connection was aborted by the software in your host machine
和接收没有数据。
我正在使用本地地址在本地计算机上测试服务器和客户端192.168.1.2
。
解决方案
不同之处在于 TLS 1.3 在 TLS 握手之后发送会话票证,而在以前的 TLS 版本中,会话票证是在 TLS 握手内发送的。因此,使用 TLS 1.3 来自服务器的数据(会话票证)将在ssock.connect(...)
完成后到达。由于您的应用程序在关闭套接字后不会读取任何数据,而未读取的connect
数据仍在底层 TCP 套接字的套接字缓冲区内。这将导致 RST 发送到服务器并导致连接重置错误。
这是从不尝试从服务器读取的应用程序的一个已知问题。如果应用程序期望来自服务器的响应并使用recv
它来获取它,这将隐式地读取会话票证。
当您不希望服务器返回任何应用程序数据时,要解决这种情况,请在关闭套接字之前正确关闭套接字。由于这将读取服务器 SSL 关闭消息,它还将隐式读取服务器之前发送的会话票证。
try:
ssock = ssock.unwrap()
except:
True
ssock.close()
推荐阅读
- kubernetes - 使用启用了 https 负载平衡器和 IAP/安全策略的 GKE 入口
- docker - 如何在 Docker 容器中设置 net.core.* 和 net.ipv4.* sysctl 属性
- javascript - 使用 Gatsby 在 React 代码中添加指向 CDN 的链接的位置
- c# - 如何从字符串调用静态类方法?
- javascript - 如何仅使用完整路径在 JavaScript 中播放音频文件
- javascript - amcharts 按天和分钟分组
- html - Bootstrap Collapse 在折叠时显示子元素
- java - Hibernate5 忽略延迟加载
- javascript - jQuery,如何传递一个 rgb 值来改变一个 CSS 背景?
- elixir - 灵丹妙药 GenStage 消费者 min_demand