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

How can I see if there's an available and active network connection in Python?

提问人:aF. 提问时间:9/22/2010 最后编辑:MendelGaF. 更新时间:4/18/2023 访问量:266724

问:

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

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

Python 网络

评论

0赞 jdizzle 9/22/2010
如果你使用的是 Python,它几乎肯定会在连接失败或超时时抛出异常。你可以尝试/抓住它,或者让它浮出水面。
1赞 inspectorG4dget 9/22/2010
@Triptych:我希望那是个玩笑,因为它行不通
2赞 S.Lott 9/22/2010
@inspectorG4dget:easy_install system_of_tubes
2赞 inspectorG4dget 9/22/2010
@aF:看看 Unutbu 的解决方案。它显示(以最快的方式)如何检查您是否能够访问 google.com。如果您的问题涉及访问 API,那么为什么不尝试访问它,设置 timeout=1?这将确切地告诉您要访问的 API 是否可访问。一旦你知道了这一点,那么你就可以继续访问API,或者等待你能够访问它的时间。
0赞 aF. 9/22/2010
就像我说的,我只需要一件简单的事情,就像 unutbu 说的那样。你不需要为此大惊小怪..

答:

10赞 Tomasz Wysocki 9/22/2010 #1

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

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

评论

2赞 cobbal 9/22/2010
“请求宽恕比请求许可更容易”
0赞 aF. 9/22/2010
这不需要那么好。我只需要尝试连接到一个站点或ping某些东西,如果它超时,瞧。我该怎么做?
0赞 Tomasz Wysocki 9/22/2010
有什么理由不能尝试连接到 API 吗?为什么在真正连接之前必须检查它?
0赞 aF. 9/22/2010
我使用 python 制作了一个 html 页面。html 页面依赖于我在 python 程序中给出的参数。如果我可以访问 api,我只需要放一些 html 代码。这就是为什么我需要事先知道。
154赞 unutbu 9/22/2010 #2

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

from urllib import request

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

对于 Python 2.x,将 import 语句替换为:import urllib2 as request

目前,8.8.8.8 是 Google 的 IP 地址之一。将 http://8.8.8.8 更改为任何可以预期快速响应的网站

此固定 IP 不会永远映射到 google.com。所以这段代码是 不坚固 - 它需要不断维护以保持其工作。

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


如果上面的固定 IP 地址不起作用,google.com 您可以通过运行

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

评论

1赞 rzetterberg 12/31/2011
只是关于“即使互联网没有”打开“,呼叫也不会超过 1 秒的注释。-报价。如果提供的 url 无效,则 DNS 查找将阻止,则情况并非如此。它仅适用于与 Web 服务器的实际连接。避免此DNS查找块的最简单方法是改用IP地址,然后保证只需要1秒:)urlopen
9赞 theamk 9/18/2013
这不再起作用。截至 2013 年 9 月,74.125.113.99 在长时间后超时,因此此函数将始终返回 False。我想谷歌已经改变了他们的网络设置。
4赞 theamk 9/20/2013
现在剩下的就很简单了。谷歌“74.125.113.99 urllib”。它将返回数以千计的开源项目,这些项目包含不正确的代码。(对我来说,只有第一页至少包含 5 个:nvpy、sweekychebot、malteseDict、upy、checkConnection)。他们现在都坏了。
4赞 theamk 9/20/2013
如果不清楚,我不建议使用此方法。旧 IP 的有效期不到 3 年。新 IP 今天有效。把它放在你的项目中,它可能会在不到 3 年的时间里再次神秘地破裂。
2赞 Jason C 10/31/2016
的。。。只要打开,然后你就解决了每个人都在这里谈论的所有问题。无需使用 IP 地址...http://google.com
5赞 mluebke 9/22/2010 #3

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

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

17赞 Kevin C 11/5/2011 #4

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

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

而且,请注意,这里的输入(引用)是您要检查的 url:我建议选择一些可以快速连接您居住的地方的东西——例如我住在韩国,所以我可能会将引用设置为 http://www.naver.com

评论

1赞 Viktor Joras 1/31/2019
如果没有可用的DNS服务器,我将等待30秒。
30赞 Def_Os 6/28/2014 #5

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

import requests

def connected_to_internet(url='http://www.google.com/', timeout=5):
    try:
        _ = requests.head(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.head(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

评论

3赞 chirale 5/6/2017
Request 是一个很棒的库。然而,与这里的许多例子不同,我会使用 IANA 的 example.com 或 example.org 作为更可靠的长期选择,因为它完全由 ICANN 控制。
0赞 Sanjiv 8/21/2019
有没有其他方法可以检查互联网运行状态。因为如果你再次固定,那么他们会阻止我们的IP。那么还有其他方法吗?google.com
1赞 howdoicode 11/13/2020
很好。我修改了这个使用方法,只得到一个HEAD响应。requests.head()
0赞 Def_Os 11/13/2020
@howdoicode,相应地编辑了我的答案。确实快得多
0赞 forresthopkinsa 4/1/2022
转让有什么理由吗?可以用 ?_ = requests.head...requests.head...
104赞 Ivelin 4/25/2015 #6

只发出 HEAD 请求会更快,因此不会获取任何 HTML。

try:
    import httplib  # python < 3.0
except:
    import http.client as httplib


def have_internet() -> bool:
    conn = httplib.HTTPSConnection("8.8.8.8", timeout=5)
    try:
        conn.request("HEAD", "/")
        return True
    except Exception:
        return False
    finally:
        conn.close()

评论

14赞 Wally 4/6/2016
只需 20 毫秒,而最高答案只需 1 秒。
11赞 thatsIch 1/5/2017
+1 如果您只想检查服务器是否可访问并响应,则下载整个页面是没有意义的。如果需要内容,请下载内容
0赞 Polv 8/18/2018
无缘无故地,使用 url '8.8' 仍然有效,显然,“8.8”或“8.8”在真正的 Web 浏览器中不起作用。
0赞 Unknown 7/28/2021
如果连接到没有 Internet 的网络,则使用 http.client 需要 30 秒而不是 5 秒,并且使用 httplib 错误地返回 True。👎
1赞 Peter Trcka 10/17/2021
conn.close()可以移动到 。这部分将执行无 regadless there is in 或 block。finallyreturntryexcept
6赞 Aziz Alto 9/4/2015 #7
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)

0赞 Jared B. 10/6/2015 #8

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()
153赞 7h3rAm 10/14/2015 #9

如果我们可以连接到某个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

正如我们所看到的,是开放的,未经过滤的。如果您是非 root 用户,请记住使用 或 Nmap 的参数来发送构建的探测数据包并确定主机是否已启动。53/tcpsudo-Pn

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

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

Netcat 确认我们可以超越 .现在我们可以在 Python 中设置一个套接字连接来检查连接:8.8.8.853/tcp8.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 的评论,timeout 现在是一个参数,并默认初始化为。3s

评论

8赞 m3nda 12/20/2015
这是最好的答案,避免了DNS解析,具有讽刺意味的是,在端口53上咨询了Google的DNS服务。
1赞 7h3rAm 4/21/2016
@AviMehenwal Google 提供此 IP 作为其免费使用的 DNS 名称解析服务的一部分。除非 Google 另有决定,否则 IP 不应更改。几年来,我一直在使用它作为替代DNS服务器,没有任何问题。
2赞 7h3rAm 11/4/2016
@JasonC 连接到 TCP/53 与通过端口 53 的 DNS 连接不同。以您的类比,应用程序使用的每个 TCP 端口都将被归类为应用程序级协议连接。不,这不是真的。通过 TCP 套接字连接到端口不是应用程序级连接。我不是在进行DNS查找,而只是在进行半TCP握手。这与进行完整的DNS查找不是一回事。
4赞 kbridge4096 7/5/2017
我们不应该调用套接字吗?close()
2赞 snitch182 2/10/2020
再次感谢您的回答。将其转换为Windows任务栏图标:gitlab.com/room150/always-on-indicator
3赞 user5779230 2/9/2016 #10

如果 localhost 已从 Try 更改为 Try,这可能不起作用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 )

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

评论

0赞 7h3rAm 4/22/2016
这是一个有趣的检查,尽管它只会识别您是否连接到网络。无论是 Internet 还是 NAT 子网仍然是一个问题。
0赞 4/23/2016
@7h3rAm,这是一个很好的观点,DCHP不需要互联网连接,我的错误。
0赞 user150471 3/6/2019
这只需要一个已收到已分配 IP 的网络 NIC 连接。与所有其他答案不同,它不需要连接到 LAN、路由器、防火墙、ISP 一直连接到另一个系统。如果 NIC 是非 DHCP 分配的地址(静态),它仍然无法显示 NIC 已连接
0赞 3/8/2019
@user150471,已经指出了,谢谢你的贡献。
1赞 t-bltg 1/22/2017 #11

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

import subprocess

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

它会安静地运行 WGET,不下载任何内容,但检查给定的远程文件是否存在于 Web 上

0赞 Seylione 2/25/2017 #12

以 Six 的答案为例,我认为我们可以以某种方式简化,这是一个重要的问题,因为新来者在高度技术性的问题中迷失了方向。

在这里,我最终将用来等待我的连接(3G,慢)每天建立一次用于我的 PV 监控。

在 Pyth3 和 Raspbian 3.4.2 下工作

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 分钟,如果达到,我会在一小时内尝试,但它是另一个脚本!

评论

0赞 kidCoder 3/20/2017
你的 Essai Var 没有被使用,是吗?
1赞 lunar_kitsune 4/20/2018 #13

最好的方法是让它检查 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("")
0赞 monok 10/24/2018 #14

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

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
5赞 Mujeeb Ishaque 5/28/2019 #15

这是我的版本

import requests

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

评论

1赞 user2561747 6/6/2019
我喜欢这个,但如果它排除了请求引发的特定超时或连接错误,那就更好了。按原样,闪电般快速的 Ctrl-C 将离线打印。
1赞 Michael H. 5/19/2021
不需要 if 语句。
0赞 Rajiv Sharma 7/29/2019 #16

这在 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")
2赞 Adam Erickson 1/2/2020 #17

现代便携式解决方案,具有以下特点: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
0赞 Soum Axetuirk 2/22/2020 #18

我在 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赞 Luv 4/30/2020 #19

对于我的项目,我使用修改后的脚本来ping谷歌公共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赞 Raushan Kumar 5/29/2020 #20

导入请求并尝试这个简单的 Python 代码。

def check_internet():
    url = 'http://www.google.com/'
    timeout = 5
    try:
        _ = requests.get(url, timeout=timeout)
        return True
    except requests.ConnectionError:
        return False

评论

0赞 Git.Coach 9/11/2020
此代码假定您已连接到 Internet,并且您的 DNS 正在响应
0赞 Webguru Media 9/10/2020 #21

通过运行

pip install --upgrade pip

使用 requests 软件包安装

pip install requests  
    import requests
    import webbrowser
    url = "http://www.youtube.com"

    timeout = 6
    try:
        request = requests.get(url, timeout=timeout)
        print("Connected to the Internet")
        print("browser is loading url")
        webbrowser.open(url)
    except (requests.ConnectionError, requests.Timeout) as exception:
       print("poor or no internet connection.")
0赞 CncMess 7/25/2022 #22

我只想参考 Ivelin 的解决方案,因为我不能在那里发表评论。

在使用旧SSL证书的python 2.7中(在我的情况下,无法更新,这是另一回事),可能会出现证书错误。在这种情况下,将“8.8.8.8”替换为“dns.google”或“8888.google”会有所帮助。

希望这也有人能帮上忙。

try:
    import httplib  # python < 3.0
except:
    import http.client as httplib


def have_internet():
    conn = httplib.HTTPSConnection("8888.google", timeout=5)
    try:
        conn.request("HEAD", "/")
        return True
    except Exception:
        return False
    finally:
        conn.close()