重复的POST请求导致错误"socket.error: (99, 'Cannot assign requested address')"。

5

我有一个部署在我的服务器上的网络服务。我想要使用不同的输入值检查该服务的结果。以下是我使用的代码:

import sys
import httplib
import urllib

apUrl = "someUrl:somePort"

fileName = sys.argv[1]
conn = httplib.HTTPConnection(apUrl)

titlesFile = open(fileName, 'r')

try:
    for title in titlesFile:

        title = title.strip()
        params = urllib.urlencode({'search': 'abcd', 'text': title})
        conn.request("POST", "/somePath/", params)
        response = conn.getresponse()
        data = response.read().strip()
        print data+"\t"+title

        conn.close()

finally:
    titlesFile.close()

这段代码在打印了同样数量的行(28233)后出现错误。错误信息:

Traceback (most recent call last):
  File "testService.py", line 19, in ?
    conn.request("POST", "/somePath/", params)
  File "/usr/lib/python2.4/httplib.py", line 810, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.4/httplib.py", line 833, in _send_request
    self.endheaders()
  File "/usr/lib/python2.4/httplib.py", line 804, in endheaders
    self._send_output()
  File "/usr/lib/python2.4/httplib.py", line 685, in _send_output
    self.send(msg)
  File "/usr/lib/python2.4/httplib.py", line 652, in send
    self.connect()
  File "/usr/lib/python2.4/httplib.py", line 636, in connect
    raise socket.error, msg
socket.error: (99, 'Cannot assign requested address')

我正在使用Python 2.4.3版本,并执行conn.close()操作。但为什么会出现此错误?


我用错误代码28233进行了谷歌搜索,并找到了这个链接:http://developerweb.net/viewtopic.php?id=5995 - BiGYaN
3个回答

12

这不是一个 Python 问题。

在 Linux 内核 2.4 中,短暂端口范围从 32768 到 61000。因此可用端口数量为 61000-32768+1 = 28233。据我所知,由于所涉及的 Web 服务非常快(实际上小于5ms),因此所有端口都被使用了。程序必须等待一到两分钟才能关闭端口。

我所做的是计算 conn.close() 的数量。当数量达到 28000 时,等待 90 秒并重置计数器。


6
正确地发现了问题,您可以在异常发生后立即调用"netstat -tn"进行验证。您会看到大量状态为"TIME_WAIT"的连接。

等待端口号再次可用的替代方法是简单地使用一个连接处理所有请求。在每次调用conn.request()之后不需要调用conn.close()。您可以一直保持连接打开,直到完成所有请求。


1
我在使用Python的请求库在Spark中执行多个POST语句时遇到了类似的问题。更糟糕的是,我在每个执行器上使用了多进程来向服务器发送POST请求。因此,在几秒钟内创建了数千个连接,每个连接需要几秒钟才能从TIME_WAIT状态转换并释放端口以供下一组连接使用。
在互联网上提供的所有可用解决方案中,有些讲述了禁用keep-alive,使用request.Session()等方法,但我发现this答案有效,它使用'Connection':'close'配置作为头参数。您可能需要将标头内容放在post命令之外的单独行中。
headers = {
        'Connection': 'close'
}
with requests.Session() as session:
response = session.post('https://xx.xxx.xxx.x/xxxxxx/x', headers=headers, files=files, verify=False)
results = response.json()
print results

这篇文章 是我对使用上述解决方案的类似问题的回答。


虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。- 来自审查 - Jonathan Eustace
明白了,Jonathan。已相应地更改答案。感谢您的意见。 - Adiga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接