Python 3.8 TLSv1.3套接字关闭导致ConnectionResetError或ConnectionAbortedError

时间:2019-12-15 01:12:23

标签: python python-3.x sockets ssl

客户端:

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在本地计算机上测试服务器和客户端。

1 个答案:

答案 0 :(得分:2)

差异是由TLS 1.3在TLS握手后发送会话票证引起的,而对于以前的TLS版本,会话票证是在TLS握手内发送的。因此,使用TLS 1.3,在完成ssock.connect(...)之后,来自服务器的数据(会话票证)将到达。由于您的应用程序在connect之后不读取任何数据,因此它将关闭套接字,而未读取的数据仍位于基础TCP套接字的套接字缓冲区中。这将导致RST发送到服务器,并在那里导致连接重置错误。

这是从未尝试从服务器读取的应用程序的已知问题。如果应用程序期望服务器发出响应,并使用recv来获取它,则这也将隐式读取会话票证。

要解决这种情况,当您不希望服务器返回任何应用程序数据时,请在关闭套接字之前对套接字进行适当的SSL关闭。由于这将读取服务器SSL关闭消息,因此还将隐式读取服务器之前发送的会话票证。

try:
    ssock = ssock.unwrap()
except:
    True
ssock.close()

有关更多信息,请参见this issuethis documentation