'requests' python 库上的 DNS 超时
DNS timeout on 'requests' python library
对于我的项目,我必须检查网站的状态(在共享主机上)。
我使用 Python 请求库。
def getStatusCode(url):
try:
return requests.head(url,timeout=0.3).status_code
except:
return -1
此代码在 MacOS 10.10 和 Python3.4 以及 url(如 http://www.google.com)下运行良好。如果我拔掉我的 ISP 电缆,我会立即得到一个异常。
在带有 Python3.4 的 Ubuntu 服务器 14.04 下,如果我拔下 ISP 电缆,我永远不会收到超时错误。 Raspbian.
同样的问题
经过一些测试,如果我将 url 替换为 IP http://216.58.212.100,Ubuntu 服务器会向我发出异常,但由于我在共享虚拟主机上,所以我不能使用IP。
经过一些研究,我发现请求库中的超时与不是由它执行而是由 OS 执行的 DNS 查找之间存在差异。
所以我的问题是解决这个问题的最漂亮的方法是什么?我是否需要在 Python 中添加额外的超时异常,例如:Timeout on a function call
谢谢
在查理的鼓励下,我post这里有两个解决方案
对于第一个,我在请求中添加了主机 header,因此我可以将 IP 地址设为 url 并避免 DNS 查找。
def getStatusCode(url):
headers = {'host': 'www.example.com'}
try:
return requests.head(url,timeout=0.3,headers=headers).status_code
except:
return -1
print(getStatusCode('http://1.2.3.4'))
第二种解决方案基于信号的使用,但分辨率为一秒。
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)
def getStatusCode(url):
try:
return requests.head(url,timeout=0.3).status_code
except:
return -1
with timeout(seconds=1):
print(getStatusCode('http://www.example.com'))
(此解决方案来自 https://whosebug.com/a/22348885/3896729 的 Thomas Ahle)
现在我对你的问题有了更好的理解 - 我认为有更好的方法是使用你的 OS ping 应用程序,这在 Python 中应该不难做到 - for example。您还应该平均 1000 次请求并查看均值、标准差、离群值等。这样做的原因是,如果一个请求需要 500 毫秒,而您想要 1 毫秒的分辨率,您将需要产生至少 500 个请求才能获得任何东西接近你想要的分辨率。
使用 Pythons urllib(2) 的问题在于它的执行效果几乎不如系统级调用,因此您将难以生成足够多的线程来获得所需的计时分辨率.
最后,我会再次检查您的商业产品结果,以确保您的结果相似。例如(无从属关系):
http://www.thinkbroadband.com/ping.
对于我的项目,我必须检查网站的状态(在共享主机上)。
我使用 Python 请求库。
def getStatusCode(url):
try:
return requests.head(url,timeout=0.3).status_code
except:
return -1
此代码在 MacOS 10.10 和 Python3.4 以及 url(如 http://www.google.com)下运行良好。如果我拔掉我的 ISP 电缆,我会立即得到一个异常。
在带有 Python3.4 的 Ubuntu 服务器 14.04 下,如果我拔下 ISP 电缆,我永远不会收到超时错误。 Raspbian.
同样的问题经过一些测试,如果我将 url 替换为 IP http://216.58.212.100,Ubuntu 服务器会向我发出异常,但由于我在共享虚拟主机上,所以我不能使用IP。
经过一些研究,我发现请求库中的超时与不是由它执行而是由 OS 执行的 DNS 查找之间存在差异。
所以我的问题是解决这个问题的最漂亮的方法是什么?我是否需要在 Python 中添加额外的超时异常,例如:Timeout on a function call
谢谢
在查理的鼓励下,我post这里有两个解决方案
对于第一个,我在请求中添加了主机 header,因此我可以将 IP 地址设为 url 并避免 DNS 查找。
def getStatusCode(url):
headers = {'host': 'www.example.com'}
try:
return requests.head(url,timeout=0.3,headers=headers).status_code
except:
return -1
print(getStatusCode('http://1.2.3.4'))
第二种解决方案基于信号的使用,但分辨率为一秒。
class timeout:
def __init__(self, seconds=1, error_message='Timeout'):
self.seconds = seconds
self.error_message = error_message
def handle_timeout(self, signum, frame):
raise TimeoutError(self.error_message)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, type, value, traceback):
signal.alarm(0)
def getStatusCode(url):
try:
return requests.head(url,timeout=0.3).status_code
except:
return -1
with timeout(seconds=1):
print(getStatusCode('http://www.example.com'))
(此解决方案来自 https://whosebug.com/a/22348885/3896729 的 Thomas Ahle)
现在我对你的问题有了更好的理解 - 我认为有更好的方法是使用你的 OS ping 应用程序,这在 Python 中应该不难做到 - for example。您还应该平均 1000 次请求并查看均值、标准差、离群值等。这样做的原因是,如果一个请求需要 500 毫秒,而您想要 1 毫秒的分辨率,您将需要产生至少 500 个请求才能获得任何东西接近你想要的分辨率。
使用 Pythons urllib(2) 的问题在于它的执行效果几乎不如系统级调用,因此您将难以生成足够多的线程来获得所需的计时分辨率.
最后,我会再次检查您的商业产品结果,以确保您的结果相似。例如(无从属关系): http://www.thinkbroadband.com/ping.