Comprobando la conexión de red

133

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?

aF.
fuente
Si está en Python, casi seguramente arrojará una excepción en caso de una falla de conexión o tiempo de espera. Puede intentar / atrapar eso, o simplemente dejar que salga a la superficie.
jdizzle
1
@Triptych: espero que haya sido una broma, porque no funciona
inspectorG4dget
1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott
2
@aF: Mira la solución de Unutbu. Muestra (de la manera más rápida posible) cómo verificar si puede acceder a google.com. Si su problema se refiere al acceso a la API, ¿por qué no intenta acceder a ella, configurando timeout = 1? Eso le dirá exactamente si la API a la que desea acceder es accesible. Una vez que sepa eso, puede continuar y acceder a la API o esperar un momento en que pueda acceder a ella.
inspectorG4dget
Como dije, solo necesitaba algo simple como dijo unutbu. No necesitas hacer tanto escándalo con esto ...
aF.

Respuestas:

132

Quizás 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 de google.com. Cambie http://216.58.192.142a cualquier sitio que se pueda esperar que responda rápidamente .

Esta IP fija no se asignará a google.com para siempre. Por lo tanto, este código no es robusto: necesitará un mantenimiento constante para que siga funcionando.

La razón por la cual el código anterior usa una dirección IP fija en lugar de un 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 en sí misma puede bloquear la llamada urllib_request.urlopendurante 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
unutbu
fuente
1
Solo una nota sobre "la llamada a urlopenno tomará mucho más de 1 segundo, incluso si Internet no está" en "". Esto no es cierto si la url proporcionada no es válida, entonces la búsqueda de DNS se bloqueará. Solo es cierto para la conexión real al servidor web. La forma más sencilla de evitar este bloque de búsqueda de DNS es utilizar la dirección IP en su lugar, luego se garantiza que solo tomará 1 segundo :)
rzetterberg
8
ESTO YA NO FUNCIONA. A partir de septiembre de 2013, 74.125.113.99 se agota después de mucho tiempo, por lo que esta función siempre devolverá False. Supongo que Google ha cambiado su red está configurada.
theamk
44
Ahora el resto es simple. Google para "74.125.113.99 urllib". Devolverá miles de proyectos de código abierto que incorporaron el código incorrecto. (para mí, solo la primera página contiene al menos 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Todos están rotos ahora.
theamk
44
Si no está claro, NO RECOMIENDO usar este método. La IP anterior era buena por menos de 3 años. La nueva IP funciona hoy. Póngalo en su proyecto, y podría romperse misteriosamente en menos de 3 años, nuevamente.
theamk
1
Er ... solo abre http://google.comy luego resuelve todos los problemas de los que todo el mundo habla aquí. No hay necesidad de usar una dirección IP ...
Jason C
106

Si podemos conectarnos a algún servidor de Internet, entonces 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 de la capa de aplicación (conexión a un servicio HTTP / FTP / IMAP)
  • Evite las llamadas a utilidades externas desde Python u otro idioma de elección (necesitamos encontrar una solución independiente del idioma que no se base en soluciones de terceros)

Para cumplir con estos, 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.8y 8.8.4.4. Podemos intentar conectarnos con cualquiera de ellos.

Un rápido Nmap del host 8.8.8.8dio 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, 53/tcpestá abierto y no filtrado. Si no es un usuario root, recuerde usar sudoo el -Pnargumento para que Nmap envíe paquetes de sonda diseñados y determine si un host está activo.

Antes de probar con Python, probemos la conectividad utilizando 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 pueden alcanzar 8.8.8.8más 53/tcp. Ahora podemos configurar una conexión de socket 8.8.8.8:53/tcpen 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 socket.error as ex:
        print(ex)
        return False

internet()

Otro enfoque podría ser enviar una sonda DNS diseñada manualmente a uno de estos servidores y esperar una respuesta. Pero, supongo, podría ser más lento en comparación debido a la caída 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 3sde forma predeterminada.

ACTUALIZACIÓN # 2: Hice pruebas rápidas para identificar la implementación más rápida y 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

Trueen 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 nuevamente 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
7h3rAm
fuente
66
Esta es la mejor respuesta, evitando la resolución DNS e, irónicamente, consultando el servicio DNS de Google en el puerto 53.
m3nda
1
@AviMehenwal Google proporciona esta IP como parte de su servicio gratuito de resolución de nombres DNS. No se supone que la IP cambie a menos que Google decida lo contrario. Lo he estado usando como un servidor DNS alternativo durante algunos años sin ningún problema.
7h3rAm
1
@Luke Gracias por señalar eso. He actualizado la respuesta para informar a los usuarios sobre la excepción y devolver False como respuesta predeterminada.
7h3rAm
2
@JasonC La conexión a TCP / 53 es diferente de la conexión DNS a través del puerto 53. Según su analogía, cada puerto TCP que utiliza una aplicación se clasificará como conexión de protocolo de nivel de aplicación. No, eso no es verdad. La conexión a través de un socket TCP a un puerto NO ES una conexión a nivel de aplicación. No estoy haciendo una búsqueda de DNS, sino solo un apretón de manos medio TCP. No es lo mismo que hacer una búsqueda completa de DNS.
7h3rAm
2
¿No deberíamos llamar close()al zócalo?
brk
60

Será más rápido simplemente hacer una solicitud HEAD para que no se obtenga HTML.
También estoy seguro de que a Google le gustaría más de esta manera :)

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
Ivelin
fuente
8
Solo toma 20 milisegundos, mientras que la respuesta superior toma 1 segundo.
Wally
8
+1 No tiene sentido descargar la página completa si solo desea verificar si el servidor es accesible y responde. Descargue el contenido si lo necesita
eso es Ich
Sin ninguna razón, usar la url '8.8' todavía funciona, lo que obviamente, '8.8' u ' 8.8 ' no funciona en un navegador web real.
Polv
2 horas buscando una solución de trabajo y luego encontré esto ... limpio y simple
Pedro Serpa
21

Como alternativa a las respuestas de ubutnu / Kevin C, uso el requestspaquete de 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
Def_Os
fuente
1
Request es una gran biblioteca. Sin embargo, a diferencia de muchos ejemplos aquí, usaría example.com o example.org de IANA como una opción a largo plazo más confiable, ya que está completamente controlada por ICANN .
chirale
¿Hay alguna otra forma de verificar el estado de ejecución de Internet? Porque si vuelves a suspirar google.comnuevamente, bloquearán nuestra IP. Entonces, ¿hay alguna otra manera?
Sanjiv
15

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 tener en cuenta, la entrada aquí (referencia) es la url que desea verificar: sugiero elegir algo que se conecte rápidamente donde vive, es decir, vivo en Corea del Sur, por lo que probablemente establecería una referencia a http: / /www.naver.com .

Kevin C
fuente
Esperaré 30 segundos si no hay un servidor DNS disponible.
Viktor Joras
10

Puede intentar descargar datos y, si falla la conexión, sabrá que algo con la conexión no está bien.

Básicamente no puede verificar si la computadora está conectada a Internet. Puede haber muchas razones para fallar, como una configuración incorrecta de DNS, firewalls, NAT. Entonces, incluso si realiza algunas pruebas, no puede garantizar que tendrá conexión con su API hasta que lo intente.

Tomasz Wysocki
fuente
2
"Es más fácil pedir perdón que permiso"
cobbal
Esto no tiene por qué ser tan bueno. Simplemente necesito tratar de conectarme a un sitio o hacer ping a algo y si me da tiempo de espera voilá. ¿Cómo puedo hacer eso?
aF.
¿Hay alguna razón por la que no puedas simplemente intentar conectarte a la API? ¿Por qué debes comprobarlo antes de una conexión real?
Tomasz Wysocki
Hago una página html usando python. La página html depende de los argumentos que doy en el programa python. Solo necesito poner un código html si puedo acceder a la api. Es por eso que necesito saber antes.
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!' )

Para python 3, use urllib.request.urlopen(host)

Aziz Alto
fuente
4

Intente la operación que intentaba hacer de todos modos. Si falla, Python debería arrojarte una excepción para avisarte.

Intentar una operación trivial primero para detectar una conexión introducirá una condición de carrera. ¿Qué sucede si la conexión a Internet es válida cuando realiza la prueba pero se cae antes de que necesite hacer un trabajo real?

mluebke
fuente
3

Esto podría no funcionar si el host local se ha cambiado de 127.0.0.1 Probar

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 localhost. Espero que ayude


fuente
Esa es una verificación interesante, aunque solo identificará si está conectado a una red. Si es Internet o una subred NAT'd seguirá siendo una pregunta.
7h3rAm
@ 7h3rAm, ese es un buen punto, el DCHP no requiere conexión a Internet, mi error.
Esto solo requiere una conexión NIC de red a la que se le haya asignado una IP. A diferencia de todas las otras respuestas, no requiere una conexión a la LAN, enrutador, firewall, ISP hasta otro sistema. Todavía no muestra que la NIC está conectada si es una dirección no asignada por DHCP (estática)
usuario150471
@ user150471, ya señaló, gracias por su contribución.
3

Aquí está mi versión

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")
Mujeeb Ishaque
fuente
1
Me gusta este, pero sería mejor si exceptuara un tiempo de espera específico o un error de conexión que surge de las solicitudes. Como está, se imprimirá un Ctrl-C ultrarrápido fuera de línea.
user2561747
2

Una solución portátil moderna con 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

O, una versión que plantea una excepción:

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
Adam Erickson
fuente
1

La mejor manera de hacerlo es hacer que verifique 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("")
lunar_kitsune
fuente
1

mi favorito, cuando ejecuta 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 se ejecuta en silencio, sin descargar nada, pero verificando que el archivo remoto dado exista en la web

neok
fuente
0

Tomando la respuesta de unutbu como punto de partida, y después de haber sido quemado en el pasado por un cambio de dirección IP "estática", 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 comprobaciones posteriores. De esa manera, la dirección IP siempre está actualizada (suponiendo que la clase se reinicialice al menos una vez cada pocos años más o menos). También le 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.). No tenga en cuenta la 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()
Jared B.
fuente
0

Tomando la respuesta de Six, creo que podríamos simplificar de alguna manera, un tema importante ya que los recién llegados se pierden en asuntos altamente técnicos.

Aquí lo que finalmente usaré para esperar a que se establezca mi conexión (3G, lenta) 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)       

funcionamiento máximo: 5 minutos si lo alcanzo, lo intentaré dentro de una hora, ¡pero es otro guión!

Seylione
fuente
tu essai var no se acostumbra, ¿verdad?
kidCoder
0

Tomando la respuesta de Ivelin y agregando un poco de verificación adicional mientras mi enrutador entrega su dirección IP 192.168.0.1 y devuelve un encabezado si no tiene conexión a Internet cuando consulta 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
monok
fuente
0

Esto funciona para mí en 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")
Rajiv Sharma
fuente
0

Agregué algunos al código de 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
Soum Axetuirk
fuente
0

Para mis proyectos, uso un script modificado para hacer ping al servidor DNS público de Google 8.8.8.8. Usando un tiempo de espera de 1 segundo y bibliotecas centrales de Python sin dependencias externas:

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()

El valor de tiempo de espera seleccionado es 1, pero puede ser un número de punto flotante de elección para fallar más fácilmente que el 1 segundo en este ejemplo.

Luv
fuente
0

importar solicitudes y probar este código simple de Python.

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