我有这个简单的代码,可与外部服务器连接。我称此功能每分钟100秒钟。一段时间后,我发现系统缺少足够的缓冲区异常。当我使用TCPView查看连接时,它以TIME_WAIT状态显示数百个与外部服务器的连接。
如果我必须发送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
答案 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操作的同时进行大量有意义的操作。