【问题标题】:DNS timeout on 'requests' python library“请求”python库的DNS超时
【发布时间】:2015-06-10 21:42:52
【问题描述】:

对于我的项目,我必须检查网站的状态(在共享主机上)。

我使用 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 Server 14.04 下,如果我拔掉我的 ISP 电缆,我永远不会收到超时错误。在 Raspbian 上也有同样的问题。

经过一些测试,如果我将 url 替换为 IP http://216.58.212.100,Ubuntu Server 会引发异常,但由于我在共享虚拟主机上,所以我无法使用 IP。

经过一些研究,我发现请求库中的超时与不是由它执行而是由操作系统执行的 DNS 查找之间存在差异。

所以我的问题是解决这个问题的最漂亮的方法是什么?我是否需要在 Python 中添加额外的超时异常,例如:Timeout on a function call

谢谢

【问题讨论】:

  • 看起来您回答了自己的问题(在 SO 上鼓励这样做)。我不知道更“漂亮”的解决方案。我会发布您的最终代码和任何有关因操作系统而异的超时的相关研究的链接(这将对阅读本文的其他人有用)。
  • 谢谢查理。像我发布的链接或here 这样的解决方案的问题是它们的分辨率至少为一秒,而我正在跳到毫秒的分辨率。也许可以根据IP伪造请求并编辑标头以避免共享托管问题。如果没有更好的解决方案,我会发布我的解决方案:)
  • 现在我很好奇 - 为什么 URL 请求需要毫秒分辨率?如果您需要并行启动数千个请求,那将需要一些工作。例如见here
  • 事实上,我正在寻找监控我的 ISP 连接。我有微断线,我想要半秒的分辨率。使用 Web 请求效率不是很高,但它确实比通过 popen 或子进程解析 ping 答案要简单。但是当我在学习 Python 时,我肯定错过了一些东西,我会接受更好的建议。

标签: python dns python-requests


【解决方案1】:

在查理的鼓励下,我在这里发布我的两个解决方案

对于第一个,我在请求标头中添加了主机,因此我可以将 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'))

(此解决方案来自 Thomas Ahle,https://stackoverflow.com/a/22348885/3896729

【讨论】:

    【解决方案2】:

    现在我对你的问题有了更好的理解——我认为有一个更好的方法是使用你的 OS ping 应用程序,这在 Python 中应该不难做到——for example。您还应该平均 1000 次请求,并查看平均值、标准差、异常值等。原因是,如果一个请求需要 500 毫秒,而您想要 1 毫秒的分辨率,则需要产生至少 500 个请求才能获得任何结果接近你想要的分辨率。

    使用 Python 的 urllib(2) 的问题在于它的性能几乎不如系统级调用,因此您将难以产生足够的线程来获得所需的时间分辨率。

    最后,我会再次检查您的商业产品的结果,以确保您的结果相似。例如(无从属关系): http://www.thinkbroadband.com/ping.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 2016-07-10
      相关资源
      最近更新 更多