我如何查看 Python 中是否存在可用且活动的网络连接?

新手上路,请多包涵

我想看看我是否可以访问在线 API,但为此,我需要能够访问 Internet。

我如何使用 Python 查看是否有连接可用且处于活动状态?

原文由 aF. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 308
2 个回答

也许你可以使用这样的东西:

 import urllib2

def internet_on():
    try:
        urllib2.urlopen('http://216.58.192.142', timeout=1)
        return True
    except urllib2.URLError as err:
        return False

目前,216.58.192.142 是 google.com 的 IP 地址之一。 _将 http://216.58.192.142 更改为可以快速响应的任何站点_。

这个固定 IP 永远不会映射到 google.com。所以这段代码并不健壮——它需要不断维护才能保持运行。

上面的代码使用固定 IP 地址而不是完全限定域名 (FQDN) 的原因是因为 FQDN 需要 DNS 查找。当机器没有可用的互联网连接时,DNS 查找本身可能会阻止对 urllib_request.urlopen 的调用超过一秒钟。感谢@rzetterberg 指出这一点。


如果上面的固定 IP 地址不起作用,您可以通过运行找到 google.com(在 unix 上)的当前 IP 地址

% dig google.com  +trace
...
google.com.     300 IN  A   216.58.192.142

原文由 unutbu 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果我们可以连接到某个 Internet 服务器,那么我们确实可以连接。然而,为了获得最快和最可靠的方法,所有解决方案至少应符合以下要求:

  • 避免 DNS 解析(我们将需要一个众所周知的 IP,并保证大部分时间可用)
  • 避免应用层连接(连接到 HTTP/FTP/IMAP 服务)
  • 避免从 Python 或其他选择的语言调用外部实用程序(我们需要提出一个不依赖第三方解决方案的语言不可知的解决方案)

为了遵守这些规定,一种方法可能是检查是否可以访问 Google 的公共 DNS 服务器 之一。这些服务器的 IPv4 地址是 8.8.8.88.8.4.4 。我们可以尝试连接到其中任何一个。

主机的快速 Nmap 8.8.8.8 给出了以下结果:

 $ sudo nmap 8.8.8.8

Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 IST
Nmap scan report for google-public-dns-a.google.com (8.8.8.8)
Host is up (0.0048s latency).
Not shown: 999 filtered ports
PORT   STATE SERVICE
53/tcp open  domain

Nmap done: 1 IP address (1 host up) scanned in 23.81 seconds

如我们所见, 53/tcp 是开放的且未过滤。如果您是非 root 用户,请记住使用 sudo-Pn 参数让 Nmap 发送精心制作的探测数据包并确定主机是否启动。

在尝试使用 Python 之前,让我们使用外部工具 Netcat 测试连接性:

 $ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!

Netcat 确认我们可以到达 8.8.8.8 超过 53/tcp 。现在我们可以在 Python 中建立一个到 8.8.8.8:53/tcp 的套接字连接来检查连接:

 import socket

def internet(host="8.8.8.8", port=53, timeout=3):
    """
    Host: 8.8.8.8 (google-public-dns-a.google.com)
    OpenPort: 53/tcp
    Service: domain (DNS/TCP)
    """
    try:
        socket.setdefaulttimeout(timeout)
        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
        return True
    except socket.error as ex:
        print(ex)
        return False

internet()

另一种方法可能是将手动制作的 DNS 探测发送到其中一个服务器并等待响应。但是,我认为,由于数据包丢失、DNS 解析失败等原因,它可能比较慢。如果您有其他想法,请发表评论。

更新 #4: 这个 公共名称服务器列表是 IP 测试的一个很好的参考。

更新 #3:异常处理更改后再次测试:

 defos.py
True
00:00:00:00.410

iamaziz.py
True
00:00:00:00.240

ivelin.py
True
00:00:00:00.109

jaredb.py
True
00:00:00:00.520

kevinc.py
True
00:00:00:00.317

unutbu.py
True
00:00:00:00.436

7h3rAm.py
True
00:00:00:00.030

更新#2:我进行了快速测试以确定该问题所有有效答案的最快和最通用的实现。这是摘要:

 $ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.487

iamaziz.py
True
00:00:00:00.335

ivelin.py
True
00:00:00:00.105

jaredb.py
True
00:00:00:00.533

kevinc.py
True
00:00:00:00.295

unutbu.py
True
00:00:00:00.546

7h3rAm.py
True
00:00:00:00.032

再一次:

 $ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'
defos.py
True
00:00:00:00.450

iamaziz.py
True
00:00:00:00.358

ivelin.py
True
00:00:00:00.099

jaredb.py
True
00:00:00:00.585

kevinc.py
True
00:00:00:00.492

unutbu.py
True
00:00:00:00.485

7h3rAm.py
True
00:00:00:00.035

True 在上面的输出中表示来自各个作者的所有这些实现都正确地识别了到 Internet 的连接。时间以毫秒分辨率显示。

更新 #1:感谢 @theamk 的评论,超时现在是一个参数并默认初始化为 3s

原文由 7h3rAm 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题