检查网络连接


133

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

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


如果您使用的是python,则几乎可以肯定会在连接失败或超时的情况下引发异常。您可以尝试/抓住它,或者只是让它浮出水面。
jdizzle 2010年

1
@Triptych:我希望那是个玩笑,因为它不起作用
inspectorG4dget 2010年

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott 2010年

2
@aF:看看Unutbu的解决方案。它显示(以最快的方式)如何检查您是否能够访问google.com。如果您的问题与访问API有关,那么为什么不尝试将其设置为timeout = 1来访问它呢?它将准确告诉您您要访问的API是否可访问。知道这一点后,就可以继续访问API或等待一段时间才能访问它。
inspectorG4dget

就像我说的,我只需要一个简单的事情,例如unutbu所说的。您无需为此大惊小怪..
aF。

Answers:


132

也许您可以使用如下方式:

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查找。当机器没有有效的Internet连接时,DNS查找本身可能会阻止呼叫urllib_request.urlopen超过一秒钟。感谢@rzetterberg指出这一点。


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

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

1
请注意,“ urlopen即使没有打开互联网,打到电话也不会花费超过1秒的时间。” 如果提供的URL无效,则不正确,则DNS查找将被阻止。这仅适用于与Web服务器的实际连接。避免此DNS查找块的最简单方法是改用IP地址,然后保证只用1秒钟:)
rzetterberg 2011年

8
这不再需要工作。自2013年9月起,长时间等待74.125.113.99超时,因此此函数将始终返回False。我想Google已经更改了他们的网络设置。
theamk 2013年

4
现在剩下的事情很简单了。Google:“ 74.125.113.99 urllib”。它将返回包含错误代码的数千个开源项目。(对我来说,仅第一页至少包含5个:nvpy,sweekychebot,malteseDict,upy,checkConnection)。他们现在都坏了。
theamk 2013年

4
如果不清楚,我不建议使用此方法。旧的IP不到3年就很好了。新的IP今天就可以使用。将其放入您的项目中,它可能会在不到三年的时间内再次神秘破灭。
theamk 2013年

1
呃...只要打开http://google.com,然后您就可以解决所有人在这里一直在谈论的所有问题。无需使用IP地址...
Jason C

106

如果我们可以连接到某些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.853/tcp。现在,我们可以8.8.8.8:53/tcp在Python中设置与的套接字连接以检查连接:

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解析失败等原因,相比而言,它可能会比较慢。如果您另有意见,请发表评论。

更新#1:感谢@theamk的注释,超时现在是一个参数,3s默认情况下初始化为。

更新#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的连接。时间以毫秒为单位显示。

更新#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

6
这是最好的答案,避免了DNS解析,讽刺的是,在53端口咨询谷歌的DNS服务
m3nda

1
@AviMehenwal Google提供此IP作为其免费使用的DNS名称解析服务的一部分。除非Google另有决定,否则不应更改IP。几年来,我一直在将其用作备用DNS服务器,而没有任何问题。
7h3rAm 2016年

1
@Luke感谢您指出这一点。我已经更新了答案,以通知用户有关异常的信息,并返回False作为默认答案。
7h3rAm

2
@JasonC连接到TCP / 53与通过端口53进行DNS连接不同。以此类推,应用程序使用的每个TCP端口都将归为应用程序级别协议连接。不,那不是真的。通过TCP套接字连接到端口不是应用程序级别的连接。我不是在进行DNS查找,而只是进行了一半的TCP握手。这与进行完整的DNS查找不同。
7h3rAm

2
我们不应该打电话close()给插座吗?
布鲁克

60

仅发出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

8
仅需20毫秒,而最佳答案则需要1秒。
沃利

8
+1如果只想检查服务器是否可以访问并响应,则下载整个页面毫无意义。如果需要内容,请下载内容
ThatsIch

毫无理由,仍然使用URL“ 8.8”仍然有效,显然,在实际的Web浏览器中,“ 8.8”或“ 8.8 ”不起作用。
波兰

2小时寻找有效的解决方案,然后我发现了这一点...干净而简单
Pedro Serpa

21

作为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

奖励:可以扩展为对网站执行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

1
Request是一个很棒的图书馆。但是,与这里的许多示例不同,我将使用IANA的example.com或example.org作为更可靠的长期选择,因为它完全由ICANN控制。
手风琴

还有其他方法可以检查互联网运行状态。因为如果您google.com再次固定,则它们将阻止我们的IP。那么还有其他方法吗?
桑吉夫

15

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

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

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


如果没有可用的DNS服务器,我将等待30秒。
维克多·乔拉斯

10

您可以尝试下载数据,如果连接失败,您将知道连接不正常。

基本上,您无法检查计算机是否已连接到Internet。失败的原因可能有很多,例如错误的DNS配置,防火墙,NAT。因此,即使您进行了一些测试,也无法保证您可以尝试使用API​​进行连接。


2
“请求宽恕比允许容易”
cobbal

这不必那么好。我只需要尝试连接到站点或ping某些东西(如果超时)。我怎样才能做到这一点?
aF。

有什么原因不能仅仅尝试连接到API?为什么必须在真正连接之前进行检查?
Tomasz Wysocki 2010年

我使用python创建了一个html页面。html页面依赖于我在python程序中提供的参数。如果可以访问api,则只需要放置一些html代码。这就是为什么我需要知道。
aF。

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!' )

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


4

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

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


3

如果本地主机已从“ 127.0.0.1 尝试”中更改,则这可能不起作用

import socket
ipaddress=socket.gethostbyname(socket.gethostname())
if ipaddress=="127.0.0.1":
    print("You are not connected to the internet!")
else:
    print("You are connected to the internet with the IP address of "+ ipaddress )

除非进行编辑,否则当您未连接到Internet时,您的计算机IP将为127.0.0.1。该代码基本上获取IP地址,然后询问它是否是localhost IP地址。希望能有所帮助


这是一个有趣的检查,尽管它只会识别您是否连接到网络。无论是Internet还是NAT子网仍然是一个问题。
7h3rAm

@ 7h3rAm,这很不错,DCHP不需要互联网连接,这是我的错。

这仅需要已分配了IP的网络NIC连接。与所有其他答案不同,它并不需要一直连接到LAN,路由器,防火墙,ISP以及其他系统。如果它不是由DHCP分配的地址(静态),则仍然无法显示NIC已连接
user150471

@ user150471,已经指出,谢谢您的贡献。

3

这是我的版本

import requests

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

1
我喜欢这一点,但是如果它排除了从请求中引发的特定超时或连接错误,那就更好了。照原样,快捷键Ctrl-C将脱机打印。
user2561747 '19

2

具有以下优点的现代便携式解决方案requests

import requests

def internet():
    """Detect an internet connection."""

    connection = None
    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
        connection = True
    except:
        print("Internet connection not detected.")
        connection = False
    finally:
        return connection

或者,一个引发异常的版本:

import requests
from requests.exceptions import ConnectionError

def internet():
    """Detect an internet connection."""

    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
    except ConnectionError as e:
        print("Internet connection not detected.")
        raise e

1

最好的方法是让它检查python在找不到网站时始终提供的IP地址。在这种情况下,这是我的代码:

import socket

print("website connection checker")
while True:
    website = input("please input website: ")
    print("")
    print(socket.gethostbyname(website))
    if socket.gethostbyname(website) == "92.242.140.2":
        print("Website could be experiencing an issue/Doesn't exist")
    else:
        socket.gethostbyname(website)
        print("Website is operational!")
        print("")

1

我最喜欢的一个,是否在群集上运行脚本

import subprocess

def online(timeout):
    try:
        return subprocess.run(
            ['wget', '-q', '--spider', 'google.com'],
            timeout=timeout
        ).returncode == 0
    except subprocess.TimeoutExpired:
        return False

这会安静地运行wget,不下载任何东西,而是检查给定的远程文件在网络上是否存在


0

unutbu的回答为起点,并且过去因“静态” IP地址更改而烦恼,我制作了一个简单的类,该类使用DNS查找(即,使用URL“ https:// www .google.com “),然后存储响应服务器的IP地址,以用于后续检查。这样,IP地址始终是最新的(假设该类至少每隔几年左右重新初始化一次)。对于这个答案,我也给予了很高的评价,它向我展示了如何获取服务器的IP地址(进行任何重定向等之后)。请忽略此解决方案的明显缺陷,在这里我将举一个最小的工作示例。:)

这是我所拥有的:

import socket

try:
    from urllib2 import urlopen, URLError
    from urlparse import urlparse
except ImportError:  # Python 3
    from urllib.parse import urlparse
    from urllib.request import urlopen, URLError

class InternetChecker(object):
    conn_url = 'https://www.google.com/'

    def __init__(self):
        pass

    def test_internet(self):
        try:
            data = urlopen(self.conn_url, timeout=5)
        except URLError:
            return False

        try:
            host = data.fp._sock.fp._sock.getpeername()
        except AttributeError:  # Python 3
            host = data.fp.raw._sock.getpeername()

        # Ensure conn_url is an IPv4 address otherwise future queries will fail
        self.conn_url = 'http://' + (host[0] if len(host) == 2 else
                                     socket.gethostbyname(urlparse(data.geturl()).hostname))

        return True

# Usage example
checker = InternetChecker()
checker.test_internet()

0

采纳“第六”的答案,我认为我们可以以某种方式简化这一重要问题,因为新来者在技术问题上迷失了。

在这里,我最终将用来等待每天一次建立连接(3G,速度很慢)以进行PV监控的设备。

使用Raspbian 3.4.2在Pyth3下工作

from urllib.request import urlopen
from time import sleep
urltotest=http://www.lsdx.eu             # my own web page
nboftrials=0
answer='NO'
while answer=='NO' and nboftrials<10:
    try:
        urlopen(urltotest)
        answer='YES'
    except:
        essai='NO'
        nboftrials+=1
        sleep(30)       

最长运行时间:如果达到5分钟,我会在一个小时的时间内尝试尝试,但这又是另一段脚本!


您的essai var不习惯,是吗?
kidCoder

0

接受Ivelin的回答并添加一些额外的检查,因为我的路由器在查询google.com时会提供其ip地址192.168.0.1,如果没有互联网连接,则返回head。

import socket

def haveInternet():
    try:
        # first check if we get the correct IP-Address or just the router's IP-Address
        info = socket.getaddrinfo("www.google.com", None)[0]
        ipAddr = info[4][0]
        if ipAddr == "192.168.0.1" :
            return False
    except:
        return False

    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False

0

这在Python3.6中对我有用

import urllib
from urllib.request import urlopen


def is_internet():
    """
    Query internet using python
    :return:
    """
    try:
        urlopen('https://www.google.com', timeout=1)
        return True
    except urllib.error.URLError as Error:
        print(Error)
        return False


if is_internet():
    print("Internet is active")
else:
    print("Internet disconnected")

0

我在Joel的代码中添加了一些内容。

    import socket,time
    mem1 = 0
    while True:
        try:
                host = socket.gethostbyname("www.google.com") #Change to personal choice of site
                s = socket.create_connection((host, 80), 2)
                s.close()
                mem2 = 1
                if (mem2 == mem1):
                    pass #Add commands to be executed on every check
                else:
                    mem1 = mem2
                    print ("Internet is working") #Will be executed on state change

        except Exception as e:
                mem2 = 0
                if (mem2 == mem1):
                    pass
                else:
                    mem1 = mem2
                    print ("Internet is down")
        time.sleep(10) #timeInterval for checking

0

对于我的项目,我使用修改后的脚本来ping google公用DNS服务器8.8.8.8。使用1秒超时和核心python库,没有外部依赖项:

import struct
import socket
import select


def send_one_ping(to='8.8.8.8'):
   ping_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
   checksum = 49410
   header = struct.pack('!BBHHH', 8, 0, checksum, 0x123, 1)
   data = b'BCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwx'
   header = struct.pack(
      '!BBHHH', 8, 0, checksum, 0x123, 1
   )
   packet = header + data
   ping_socket.sendto(packet, (to, 1))
   inputready, _, _ = select.select([ping_socket], [], [], 1.0)
   if inputready == []:
      raise Exception('No internet') ## or return False
   _, address = ping_socket.recvfrom(2048)
   print(address) ## or return True


send_one_ping()

选择超时值是1,但也可以是选择的浮点数比在此实例中1秒更容易失败。


0

导入请求并尝试使用此简单的python代码。

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.