客户端:
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()
行的执行速度。
如果我根据数据的大小在ssocket.close()
之前放置适量的time.sleep
,那么我不会出错。否则,服务器将获得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 关闭。由于这将读取服务器SSL关闭消息,因此它还将隐式读取服务器之前发送的会话票证。
try:
ssock = ssock.unwrap()
except:
True
ssock.close()
有关详细信息,另请参阅此问题和本文档。
当应用程序使用证书通过 gunicorn 运行时,我遇到了类似的问题。jsondecodeerror问题随机来到客户端,即响应为空。唯一使用TLS 1.2的东西。
解决方案很简单,我在uwsgi上部署了应用程序,问题消失了