为什么Python http请求会创建TIME_WAIT连接?

Sam*_*a K 4 python python-requests

我有这个简单的代码,它与外部服务器连接。我称这个函数为每分钟 100 秒。一段时间后,我收到系统缺少足够缓冲区的异常。当我使用 TCPView 查看连接时,它显示数百个到外部服务器的连接处于 TIME_WAIT 状态。

  1. 为什么会发生这种情况?
  2. 如果我要发送100个请求,那么python request模块不适合吗?那我该怎么办?

      def sendGetRequest(self, url, payload):
    
            success = True
            url = self.generateUrl(url)
            result = requests.get(url, params=urllib.parse.urlencode(payload))
            code = result.status_code
            text = result.text
    
            if code < 200 or code >= 300:
                success = False
    
            result.close()
            return success, code, text
    
    Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Mar*_*ers 7

requests 您正在关闭在客户端打开的许多连接,而服务器希望重新使用它们。

由于HTTP是TCP协议,是一种双向协议,在客户端关闭套接字意味着套接字还不能完全关闭,直到另一端(服务器端)确认连接已正确关闭。在与服务器交换确认之前(或者直到超时,设置为达到最大段生存期的 2 倍),套接字将保持在该TIME_WAIT状态。在 HTTP 中,关闭通常发生在服务器端,响应完成后;服务器将等待您的客户端确认关闭。

您会看到很多这样的内容,因为每个新连接都必须使用新的本地端口号。服务器不会遇到几乎相同的问题,因为它对传入请求使用固定端口号,并且即使可能存在任意数量的未完成连接状态,该单个端口号也可以接受更多连接TIME_WAIT。另一方面,大量本地传出端口TIME_WAIT意味着您最终将用完可连接的本地端口。

这并不是 Python 或requests.

相反,您应该做的是最小化连接数量并最小化关闭。现代 HTTP 服务器期望您为多个请求重用连接。您想要使用一个requests.Session()对象,因此它可以为您管理连接,然后不要自己关闭连接。

您还可以通过使用标准功能来大大简化您的功能requestsparams例如,已经处理了 url 编码,并且比较已经为您提供了一个可以直接分配给的布尔值success

session = requests.Session()

def sendGetRequest(self, url, payload):
    result = session.get(self.generateUrl(url), params=payload)
    success = 200 <= result.status_code < 300
    return success, result.status_code, result.text
Run Code Online (Sandbox Code Playgroud)

请注意,3xx状态代码已经自动处理,因此您可以使用response.ok

def sendGetRequest(self, url, payload):
    result = session.get(self.generateUrl(url), params=payload)
    return result.ok, result.status_code, result.text
Run Code Online (Sandbox Code Playgroud)

接下来,您可能需要考虑使用asyncio协程(并且aiohttp仍然使用会话)来发出所有这些检查请求。这样,您的代码不必在每次请求-响应往返完成时都处于空闲状态,而是可以在该间隔期间执行其他操作。我构建的应用程序可以毫不费力地一次处理 1000 个并发 HTTP 请求,同时在缓慢的网络 I/O 操作完成的同时执行大量有意义的操作。