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