python - socket - Comprobando la conexión de red
socket python 3 español (13)
Como alternativa a las respuestas de ubutnu / Kevin C, utilizo el paquete de requests
esta manera:
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
Bonificación: esto se puede extender a esta función que hace ping a un sitio web.
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
Quiero ver si puedo acceder a una API en línea, pero para eso necesito tener acceso a Internet.
¿Cómo puedo ver si hay una conexión disponible y activa usando Python?
Esto podría no funcionar si el localhost ha sido cambiado desde 127.0.0.1
Prueba
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 )
A menos que se edite, la IP de su computadora será 127.0.0.1 cuando no esté conectada a Internet. Este código básicamente obtiene la dirección IP y luego pregunta si es la dirección IP del host local. Espero que ayude
La mejor forma de hacerlo es hacer que contrasta con una dirección IP que python siempre proporciona si no puede encontrar el sitio web. En este caso, este es mi código:
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("")
Pruebe la operación que estaba intentando hacer de todos modos. Si falla, python debería lanzarte una excepción para avisarte.
Intentar alguna operación trivial primero para detectar una conexión introducirá una condición de carrera. ¿Qué ocurre si la conexión a Internet es válida cuando realiza la prueba, pero baja antes de que necesite realizar el trabajo real?
Será más rápido hacer una solicitud HEAD para que no se obtenga HTML.
También estoy seguro de que Google lo preferiría así :)
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
Si podemos conectarnos a algún servidor de Internet, entonces sí tenemos conectividad. Sin embargo, para el enfoque más rápido y confiable, todas las soluciones deben cumplir con los siguientes requisitos, como mínimo:
- Evite la resolución de DNS (necesitaremos una IP que sea conocida y garantizada para estar disponible la mayor parte del tiempo)
- Evite las conexiones basadas en la capa de aplicación (conectándose a un servicio HTTP / FTP / IMAP)
- Evite las llamadas a servicios externos desde Python u otro idioma de elección (tenemos que encontrar una solución independiente del idioma que no dependa de soluciones de terceros)
Para cumplir con esto, un enfoque podría ser verificar si uno de los servidores DNS públicos de Google es accesible. Las direcciones IPv4 para estos servidores son 8.8.8.8
y 8.8.4.4
. Podemos intentar conectarnos con cualquiera de ellos.
Un Nmap rápido del host 8.8.8.8
dio el siguiente resultado:
$ 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
Como podemos ver, TCP / 53 está abierto y no filtrado. Si usted no es un usuario root, recuerde usar sudo
o el argumento -Pn
para que Nmap envíe paquetes de prueba diseñados y determine si el host está activo.
Antes de intentar con Python, probemos la conectividad usando una herramienta externa, Netcat:
$ nc 8.8.8.8 53 -zv
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
Netcat confirma que podemos alcanzar 8.8.8.8
sobre TCP / 53. Ahora podemos configurar una conexión de socket a 8.8.8.8:53/TCP en Python para verificar la conexión:
>>> 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 Exception as ex:
... print ex.message
... return False
...
>>> internet()
True
>>>
Otro enfoque podría ser enviar una sonda de DNS manual a uno de estos servidores y esperar la respuesta. Pero, supongo, podría ser más lento en comparación debido a caídas de paquetes, fallas en la resolución de DNS, etc. Comente si piensa lo contrario.
ACTUALIZACIÓN # 1: Gracias al comentario de @ theamk, el tiempo de espera ahora es un argumento y se inicializa a 3s por defecto.
ACTUALIZACIÓN # 2: Hice pruebas rápidas para identificar la implementación más rápida y más genérica de todas las respuestas válidas a esta pregunta. Aquí está el resumen:
$ 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
Y una vez más:
$ 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
en el resultado anterior significa que todas estas implementaciones de los respectivos autores identifican correctamente la conectividad a Internet. El tiempo se muestra con una resolución de milisegundos.
ACTUALIZACIÓN # 3: Probado de nuevo después del cambio de manejo de excepciones:
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
Simplemente puede tratar de descargar datos, y si falla la conexión sabrá que algo con conexión no está bien.
Básicamente no puede verificar si la computadora está conectada a internet. Puede haber muchas razones para fallas, como configuración de DNS incorrecta, firewalls, NAT. Incluso si realiza algunas pruebas, no puede garantizar que tendrá conexión con su API hasta que lo intente.
Solo para actualizar lo que dijo unutbu para el nuevo código en Python 3.2
def check_connectivity(reference):
try:
urllib.request.urlopen(reference, timeout=1)
return True
except urllib.request.URLError:
return False
Y, solo para observar, la entrada aquí (referencia) es la url que desea verificar: sugiero que elija algo que se conecte rápidamente en su lugar de residencia, es decir, vivo en Corea del Sur, por lo que probablemente haga referencia a http: / / www.naver.com .
Tal vez podrías usar algo como esto:
import urllib2
def internet_on():
try:
urllib2.urlopen(''http://216.58.192.142'', timeout=1)
return True
except urllib2.URLError as err:
return False
Actualmente, 216.58.192.142 es una de las direcciones IP para google.com. Cambie http://216.58.192.142
a cualquier sitio que se pueda esperar que responda rápidamente .
Esta IP fija no se correlacionará con google.com para siempre. Por lo tanto, este código no es robusto; necesitará mantenimiento constante para que siga funcionando.
La razón por la que el código anterior utiliza una dirección IP fija en lugar del nombre de dominio completo (FQDN) es porque un FQDN requeriría una búsqueda de DNS. Cuando la máquina no tiene una conexión a Internet que funcione, la búsqueda de DNS puede bloquear la llamada a urllib_request.urlopen
por más de un segundo. Gracias a @rzetterberg por señalar esto.
Si la dirección IP fija anterior no funciona, puede encontrar una dirección IP actual para google.com (en Unix) ejecutando
% dig google.com +trace
...
google.com. 300 IN A 216.58.192.142
Tomando la respuesta de Six, creo que podríamos simplificar de alguna manera, una cuestión importante ya que los recién llegados se pierden en cuestiones altamente técnicas.
Aquí lo que finalmente utilizaré para esperar a que mi conexión (3G, lenta) se establezca una vez al día para mi monitoreo PV.
Funciona bajo Pyth3 con 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)
Máxima ejecución: 5 minutos si lo alcanzo lo intentaré en una hora, ¡pero es otro guión!
Tomando la respuesta de unutbu como punto de partida, y habiendo sido quemado en el pasado por una dirección de IP "estática" cambiante, hice una clase simple que verifica una vez usando una búsqueda de DNS (es decir, usando la URL " https: // www .google.com "), y luego almacena la dirección IP del servidor que responde para su uso en controles posteriores. De esta forma, la dirección IP siempre estará actualizada (suponiendo que la clase se reinicialice al menos una vez cada tantos años). También doy crédito a gawry por esta respuesta , que me mostró cómo obtener la dirección IP del servidor (después de cualquier redirección, etc.). Por favor, ignore el aparente hackiness de esta solución, voy por un ejemplo de trabajo mínimo aquí. :)
Esto es lo que tengo:
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()
mi favorito, al ejecutar scripts en un clúster o no
import subprocess
def online(timeout):
try:
return subprocess.run([''wget'', ''-q'', ''--spider'', ''google.com''], timeout=timeout).returncode == 0
except subprocess.TimeoutExpired:
return False
esto ejecuta wget silenciosamente, no descarga nada sino que comprueba que el archivo remoto dado existe en la web
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!'' )
Para python 3, use urllib.request.urlopen(host)