检查网络连接

aF.*_*aF. 118 python networking

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

如何使用Python查看是否存在可用且活动的连接?

unu*_*tbu 121

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

import urllib2

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

目前,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的当前IP地址(在unix上)

% dig google.com  +trace 
...
google.com.     300 IN  A   216.58.192.142
Run Code Online (Sandbox Code Playgroud)

  • 这个没有更长的工作.截至2013年9月,http://74.125.113.99经过很长时间后,所以此功能将始终返回False.我想谷歌已经改变了他们的网络设置. (7认同)
  • 其余的很简单.谷歌为"74.125.113.99 urllib".它将返回数千个包含错误代码的开源项目.(对我来说,只有第一页包含至少5:nvpy,sweekychebot,malteseDict,upy,checkConnection).他们现在都破了. (4认同)
  • 如果不清楚,我不推荐使用这种方法.旧IP在不到3年的时间内表现良好.新IP今天有效.把它放在你的项目中,它可能会在不到3年的时间内神秘地破裂. (4认同)
  • 呃...只要打开`http://google.com`,然后你就解决了大家一直在这里谈论的所有问题。不需要使用IP地址... (2认同)

7h3*_*rAm 94

如果我们可以连接到某个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
Run Code Online (Sandbox Code Playgroud)

我们可以看到,TCP/53是开放的,未经过滤.如果您是非root用户,请记住使用sudo-PnNmap 的参数发送精心设计的探测数据包并确定主机是否已启动.

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

$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Run Code Online (Sandbox Code Playgroud)

Netcat确认我们可以8.8.8.8通过TCP/53 达到目标.现在我们可以在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()
Run Code Online (Sandbox Code Playgroud)

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

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

更新#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
Run Code Online (Sandbox Code Playgroud)

再一次:

$ 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
Run Code Online (Sandbox Code Playgroud)

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

更新#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
Run Code Online (Sandbox Code Playgroud)

  • 这是最好的答案,避免DNS解析,具有讽刺意味的是,在端口53上咨询谷歌的DNS服务. (2认同)
  • @JasonC连接到TCP / 53与通过端口53进行DNS连接不同。类似地,应用程序使用的每个TCP端口都将归为应用程序级别协议连接。不,那不是真的。通过TCP套接字连接到端口不是应用程序级别的连接。我不是在进行DNS查找,而只是进行了一半的TCP握手。这与进行完整的DNS查找不同。 (2认同)
  • 我们不应该在套接字上调用 `close()` 吗? (2认同)
  • 再次感谢您的回答。将其变成 Windows 任务栏图标:https://gitlab.com/room150/always-on-indicator (2认同)

Ive*_*lin 54

只发出一个HEAD请求会更快,因此不会获取任何HTML.
此外,我相信谷歌会更喜欢这样:)

try:
    import httplib
except:
    import http.client as httplib

def have_internet():
    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False
Run Code Online (Sandbox Code Playgroud)

  • 仅需20毫秒,而最高答案需要1秒. (8认同)
  • +1如果您只想检查服务器是否可访问并响应,则下载整个页面没有任何意义.如果您需要内容,请下载内容 (7认同)

Def*_*_Os 19

作为ubutnu/Kevin C答案的替代方案,我使用这样的requests包:

import requests

def connected_to_internet(url='http://www.google.com/', timeout=5):
    try:
        _ = requests.get(url, timeout=timeout)
        return True
    except requests.ConnectionError:
        print("No internet connection available.")
    return False
Run Code Online (Sandbox Code Playgroud)

奖励:这可以扩展到ping这个网站的功能.

def web_site_online(url='http://www.google.com/', timeout=5):
    try:
        req = requests.get(url, timeout=timeout)
        # HTTP errors are not raised by default, this statement does that
        req.raise_for_status()
        return True
    except requests.HTTPError as e:
        print("Checking internet connection failed, status code {0}.".format(
        e.response.status_code))
    except requests.ConnectionError:
        print("No internet connection available.")
    return False
Run Code Online (Sandbox Code Playgroud)

  • Request 是一个很棒的库。然而,与这里的许多示例不同,我将使用 [IANA 的 example.com](https://www.iana.org/domains/reserved) 或 example.org 作为更可靠的长期选择,因为它完全由 [ICANN]( https://en.wikipedia.org/wiki/ICANN)。 (2认同)

Kev*_*n C 16

只是为了更新unutbu在Python 3.2中为新代码所说的内容

def check_connectivity(reference):
    try:
        urllib.request.urlopen(reference, timeout=1)
        return True
    except urllib.request.URLError:
        return False
Run Code Online (Sandbox Code Playgroud)

而且,请注意,这里的输入(参考)是你要检查的网址:我建议选择一些快速连接的东西 - 即我住在韩国,所以我可能会设置参考http:/ /www.naver.com.


Tom*_*cki 9

您可以尝试下载数据,如果连接失败,您将知道连接的某些事情并不正常.

基本上你无法检查计算机是否连接到互联网.失败可能有很多原因,例如错误的DNS配置,防火墙,NAT.因此,即使您进行了一些测试,也无法确保在尝试之前与API建立连接.

  • “请求原谅比获得许可更容易” (2认同)

Azi*_*lto 6

import urllib

def connected(host='http://google.com'):
    try:
        urllib.urlopen(host)
        return True
    except:
        return False

# test
print( 'connected' if connected() else 'no internet!' )
Run Code Online (Sandbox Code Playgroud)

对于python 3,请使用 urllib.request.urlopen(host)


mlu*_*bke 5

无论如何都要尝试您尝试执行的操作。如果失败,python 应该抛出一个异常让你知道。

首先尝试一些微不足道的操作来检测连接将引入竞争条件。如果互联网连接在您测试时有效,但在您需要进行实际工作之前就断开了怎么办?


Muj*_*que 5

这是我的版本

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")
Run Code Online (Sandbox Code Playgroud)