Python 检查网络连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3764291/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Checking network connection
提问by aF.
I want to see if I can access an online API, but for that I need to have Internet access.
我想看看我是否可以访问在线 API,但为此我需要访问 Internet。
How can I see if there's a connection available and active using Python?
如何使用 Python 查看是否有可用连接并处于活动状态?
采纳答案by unutbu
Perhaps you could use something like this:
也许你可以使用这样的东西:
import urllib2
def internet_on():
try:
urllib2.urlopen('http://216.58.192.142', timeout=1)
return True
except urllib2.URLError as err:
return False
Currently, 216.58.192.142 is one of the IP addresses for google.com. Change http://216.58.192.142to whatever site can be expected to respond quickly.
目前,216.58.192.142 是 google.com 的 IP 地址之一。更改http://216.58.192.142到任何可以预期快速响应的站点。
This fixed IP will not map to google.com forever. So this code is not robust -- it will need constant maintenance to keep it working.
这个固定 IP 不会永远映射到 google.com。所以这段代码并不健壮——它需要不断的维护才能保持工作。
The reason why the code above uses a fixed IP address instead of fully qualified domain name (FQDN) is because a FQDN would require a DNS lookup. When the machine does not have a working internet connection, the DNS lookup itself may block the call to urllib_request.urlopenfor more than a second. Thanks to @rzetterberg for pointing this out.
上面的代码使用固定 IP 地址而不是完全限定域名 (FQDN) 的原因是因为 FQDN 需要 DNS 查找。当机器没有可用的互联网连接时,DNS 查找本身可能会阻止呼叫urllib_request.urlopen超过一秒钟。感谢@rzetterberg 指出这一点。
If the fixed IP address above is not working, you can find a current IP address for google.com (on unix) by running
如果上面的固定 IP 地址不起作用,您可以通过运行找到 google.com(在 unix 上)的当前 IP 地址
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
回答by Tomasz Wysocki
You can just try to download data, and if connection fail you will know that somethings with connection isn't fine.
您可以尝试下载数据,如果连接失败,您就会知道连接不正常。
Basically you can't check if computer is connected to internet. There can be many reasons for failure, like wrong DNS configuration, firewalls, NAT. So even if you make some tests, you can't have guaranteed that you will have connection with your API until you try.
基本上你不能检查计算机是否连接到互联网。失败的原因可能有很多,例如错误的 DNS 配置、防火墙、NAT。因此,即使您进行了一些测试,在您尝试之前,您也无法保证您会与 API 建立连接。
回答by mluebke
Try the operation you were attempting to do anyway. If it fails python should throw you an exception to let you know.
无论如何都要尝试您尝试执行的操作。如果失败,python 应该抛出一个异常让你知道。
To try some trivial operation first to detect a connection will be introducing a race condition. What if the internet connection is valid when you test but goes down before you need to do actual work?
首先尝试一些微不足道的操作来检测连接将引入竞争条件。如果互联网连接在您测试时有效,但在您需要进行实际工作之前就断开了怎么办?
回答by Kevin C
Just to update what unutbu said for new code in Python 3.2
只是为了更新 unutbu 对 Python 3.2 中的新代码所说的话
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
And, just to note, the input here (reference) is the url that you want to check: I suggest choosing something that connects fast where you live -- i.e. I live in South Korea, so I would probably set reference to http://www.naver.com.
而且,请注意,此处的输入(参考)是您要检查的网址:我建议选择可以快速连接您居住的地方的东西 - 即我住在韩国,所以我可能会设置对http:/ /www.naver.com。
回答by Def_Os
As an alternative to ubutnu's/Kevin C answers, I use the requestspackage like this:
作为 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
Bonus: this can be extended to this function that pings a website.
奖励:这可以扩展到 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
回答by Ivelin
It will be faster to just make a HEAD request so no HTML will be fetched.
Also I am sure google would like it better this way :)
仅发出 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
回答by Aziz Alto
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!' )
For python 3, use urllib.request.urlopen(host)
对于 python 3,使用 urllib.request.urlopen(host)
回答by Jared B.
Taking unutbu's answeras a starting point, and having been burned in the past by a "static" IP address changing, I've made a simple class that checks once using a DNS lookup (i.e., using the URL "https://www.google.com"), and then stores the IP address of the responding server for use on subsequent checks. That way, the IP address is always up to date (assuming the class is re-initialized at least once every few years or so). I also give credit to gawry for this answer, which showed me how to get the server's IP address (after any redirection, etc.). Please disregard the apparent hackiness of this solution, I'm going for a minimal working example here. :)
以unutbu 的答案为起点,并且过去因“静态”IP 地址更改而被烧毁,我制作了一个简单的类,该类使用 DNS 查找(即,使用 URL“ https://www .google.com"),然后存储响应服务器的 IP 地址以供后续检查使用。这样,IP 地址始终是最新的(假设该类至少每隔几年重新初始化一次)。我也将这个答案归功于 gawry ,它向我展示了如何获取服务器的 IP 地址(在任何重定向等之后)。请忽略此解决方案明显的hackiness,我将在这里寻找一个最小的工作示例。:)
Here is what I have:
这是我所拥有的:
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()
回答by 7h3rAm
If we can connect to some Internet server, then we indeed have connectivity. However, for the fastest and most reliable approach, all solutions should comply with the following requirements, at the very least:
如果我们可以连接到某个 Internet 服务器,那么我们确实可以连接。但是,对于最快和最可靠的方法,所有解决方案至少应符合以下要求:
- Avoid DNS resolution (we will need an IP that is well-known and guaranteed to be available for most of the time)
- Avoid application layer connections (connecting to an HTTP/FTP/IMAP service)
- Avoid calls to external utilities from Python or other language of choice (we need to come up with a language-agnostic solution that doesn't rely on third-party solutions)
- 避免 DNS 解析(我们需要一个众所周知的 IP,并保证大部分时间都可用)
- 避免应用层连接(连接到 HTTP/FTP/IMAP 服务)
- 避免从 Python 或其他选择的语言调用外部实用程序(我们需要提出一种不依赖于第三方解决方案的语言无关的解决方案)
To comply with these, one approach could be to, check if one of the Google's public DNS serversis reachable. The IPv4 addresses for these servers are 8.8.8.8and 8.8.4.4. We can try connecting to any of them.
为了遵守这些规定,一种方法可能是检查是否可以访问Google 的公共 DNS 服务器之一。这些服务器的 IPv4 地址是8.8.8.8和8.8.4.4。我们可以尝试连接到其中任何一个。
A quick Nmap of the host 8.8.8.8gave below result:
主机的快速 Nmap8.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
As we can see, 53/tcpis open and non-filtered. If you are a non-root user, remember to use sudoor the -Pnargument for Nmap to send crafted probe packets and determine if a host is up.
如我们所见,53/tcp是开放的且未过滤的。如果您是非 root 用户,请记住使用sudo或-PnNmap的参数来发送精心制作的探测数据包并确定主机是否已启动。
Before we try with Python, let's test connectivity using an external tool, Netcat:
在我们尝试使用 Python 之前,让我们使用外部工具 Netcat 测试连接性:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat confirms that we can reach 8.8.8.8over 53/tcp. Now we can set up a socket connection to 8.8.8.8:53/tcp in Python to check connection:
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()
Another approach could be to send a manually crafted DNS probe to one of these servers and wait for a response. But, I assume, it might prove slower in comparison due to packet drops, DNS resolution failure, etc. Please comment if you think otherwise.
另一种方法可能是将手动制作的 DNS 探测发送到其中一个服务器并等待响应。但是,我认为,由于数据包丢失、DNS 解析失败等原因,相比之下它可能会更慢。如果您不这么认为,请发表评论。
UPDATE #1: Thanks to @theamk's comment, timeout is now an argument and initialized to 3s by default.
更新 #1:感谢@theamk 的评论,超时现在是一个参数,默认情况下初始化为 3s。
UPDATE #2: I did quick tests to identify the fastest and most generic implementation of all valid answers to this question. Here's the summary:
更新 #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
And once more:
再一次:
$ 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
Truein the above output signifies that all these implementations from respective authors correctly identify connectivity to the Internet. Time is shown with milliseconds resolution.
True在上面的输出中表示来自各自作者的所有这些实现都正确识别了与 Internet 的连接。时间以毫秒分辨率显示。
UPDATE #3: Tested again after the exception handling change:
更新 #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
回答by 7h3rAm
This might not work if the localhost has been changed from 127.0.0.1Try
如果 localhost 已从127.0.0.1Try更改,这可能不起作用
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 )
Unless edited , your computers IP will be 127.0.0.1 when not connected to the internet. This code basically gets the IP address and then asks if it is the localhost IP address . Hope that helps
除非已编辑,否则您的计算机 IP 在未连接到 Internet 时将为 127.0.0.1。这段代码基本上是获取 IP 地址,然后询问它是否是 localhost IP 地址。希望有帮助

