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

时间:2019-07-08 16:27:19

标签: python python-requests

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

  1. 为什么会这样?
  2. 如果我必须发送100个请求,python请求模块是否不合适,那我该怎么办?

      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
    

enter image description here

1 个答案:

答案 0 :(得分:2)

您正在关闭通过requests 在客户端打开的许多连接,服务器希望这些连接可以重新使用。

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

您会在旁边看到其中的很多,因为每个新连接都必须使用新的本地端口号。服务器看不到几乎相同的问题,因为它使用固定的端口号处理传入的请求,并且即使可能存在许多未完成的TIME_WAIT连接状态,单个端口号也可以接受更多连接。另一方面,TIME_WAIT中的许多本地传出端口意味着您最终将用尽本地端口进行连接。

这不是Python或requests 所独有的。

您应该做的是最小化连接数并最小化关闭。现代HTTP服务器希望您重用连接以处理多个请求。您想使用requests.Session() object,以便它可以为您管理连接,然后自己关闭连接。

您还可以使用标准的requests功能来大大简化功能;例如,params已经可以处理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

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

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

接下来,您可能要考虑使用asyncio coroutines(和aiohttp,仍在使用会话)发出所有这些检查请求。这样,您的代码不必在每次请求-响应往返过程中都处于空闲状态,而是可以在此期间进行其他操作。我构建的应用程序可以一次处理数千个并发HTTP请求,而不会花很多时间,同时在完成缓慢的网络I / O操作的同时进行大量有意义的操作。