multiping - ping con python
Pinging servidores en Python (22)
En Python, ¿hay alguna manera de hacer ping a un servidor a través de ICMP y devolver TRUE si el servidor responde, o FALSE si no hay respuesta?
Aquí hay una solución que usa el módulo de subprocess
de Python y la herramienta ping
CLI proporcionada por el sistema operativo subyacente. Probado en Windows y Linux. Soporte para configurar un tiempo de espera de red. No necesita privilegios de administrador (al menos en Windows y Linux).
import platform
import subprocess
def ping(host, network_timeout=3):
"""Send a ping packet to the specified host, using the system "ping" command."""
args = [
''ping''
]
platform_os = platform.system()
if platform_os == ''Windows'':
args.extend([''-n'', ''1''])
args.extend([''-w'', str(network_timeout * 1000)])
elif platform_os in (''Linux'', ''Darwin''):
args.extend([''-c'', ''1''])
args.extend([''-W'', str(network_timeout)])
else:
raise NotImplemented(''Unsupported OS: {}''.format(platform_os))
args.append(host)
try:
if platform_os == ''Windows'':
output = subprocess.run(args, check=True, universal_newlines=True).stdout
if output and ''TTL'' not in output:
return False
else:
subprocess.run(args, check=True)
return True
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
return False
Asegúrese de que pyping está instalado o instálelo pip install pyping
#!/usr/bin/python
import pyping
response = pyping.ping(''Your IP'')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
Como me gusta que mi programa Python sea universal en la versión 2.7 y 3.x y en la plataforma Linux, Mac OS y Windows, tuve que modificar los ejemplos existentes.
# shebang does not work over all platforms
# ping.py 2016-02-25 Rudolf
# subprocess.call() is preferred to os.system()
# works under Python 2.7 and 3.4
# works under Linux, Mac OS, Windows
def ping(host):
"""
Returns True if host responds to a ping request
"""
import subprocess, platform
# Ping parameters as function of OS
ping_str = "-n 1" if platform.system().lower()=="windows" else "-c 1"
args = "ping " + " " + ping_str + " " + host
need_sh = False if platform.system().lower()=="windows" else True
# Ping
return subprocess.call(args, shell=need_sh) == 0
# test call
print(ping("192.168.17.142"))
Después de mirar alrededor, terminé escribiendo mi propio módulo de ping, que está diseñado para monitorear un gran número de direcciones, es asíncrono y no usa muchos recursos del sistema. Puede encontrarlo aquí: https://github.com/romana/multi-ping/ Tiene licencia de Apache, por lo que puede usarlo en su proyecto de la forma que mejor le parezca.
Las razones principales para implementar las mías son las restricciones de los otros enfoques:
- Muchas de las soluciones mencionadas aquí requieren una ejecución de una utilidad de línea de comandos. Esto es bastante ineficiente y consume muchos recursos si necesita monitorear un gran número de direcciones IP.
- Otros mencionan algunos módulos anteriores de python ping. Los miré y al final, todos tenían algún problema o el otro (como no establecer correctamente las ID de los paquetes) y no manejaban el envío de grandes cantidades de direcciones.
El ping ICMP programático es complicado debido a los privilegios elevados requeridos para enviar paquetes ICMP sin procesar, y llamar a ping
binary es feo. Para la supervisión del servidor, puede lograr el mismo resultado utilizando una técnica llamada TCP ping :
# pip3 install tcping
>>> from tcping import Ping
# Ping(host, port, timeout)
>>> ping = Ping(''212.69.63.54'', 22, 60)
>>> ping.ping(3)
Connected to 212.69.63.54[:22]: seq=1 time=23.71 ms
Connected to 212.69.63.54[:22]: seq=2 time=24.38 ms
Connected to 212.69.63.54[:22]: seq=3 time=24.00 ms
Internamente, esto simplemente establece una conexión TCP al servidor de destino y lo descarta inmediatamente, midiendo el tiempo transcurrido. Esta implementación particular es un poco limitada ya que no maneja puertos cerrados, pero para sus propios servidores funciona bastante bien.
Este script funciona en Windows y debería funcionar en otros sistemas operativos: funciona en Windows, Debian y macosx, necesita una prueba en Solaris.
import os
import platform
def isUp(hostname):
giveFeedback = False
if platform.system() == "Windows":
response = os.system("ping "+hostname+" -n 1")
else:
response = os.system("ping -c 1 " + hostname)
isUpBool = False
if response == 0:
if giveFeedback:
print hostname, ''is up!''
isUpBool = True
else:
if giveFeedback:
print hostname, ''is down!''
return isUpBool
print(isUp("example.com")) #Example domain
print(isUp("localhost")) #Your computer
print(isUp("invalid.example.com")) #Unresolvable hostname: https://tools.ietf.org/html/rfc6761
print(isUp("192.168.1.1")) #Pings local router
print(isUp("192.168.1.135")) #Pings a local computer - will differ for your network
Hay un módulo llamado pyping que puede hacer esto. Se puede instalar con pip
pip install pyping
Sin embargo, es bastante simple de usar cuando se utiliza este módulo, necesita acceso a la raíz debido al hecho de que está elaborando paquetes sin procesar bajo el capó.
import pyping
r = pyping.ping(''google.com'')
if r.ret_code == 0:
print("Viagra")
else:
print("Promescent")
Me gustó ping3 https://github.com/kyan001/ping3 Muy simple y conveniente!
from ping3 import ping, verbose_ping
ping(''example.com'') # Returns delay in seconds.
>>>0.215697261510079666
Mi reducción usando ideas de respuestas en esta publicación pero solo usando el módulo de subproceso recomendado más nuevo y python3:
import subprocess
import platform
operating_sys = platform.system()
nas = ''192.168.0.10''
def ping(ip):
ping_command = [''ping'', ip, ''-n 1''] if operating_sys == ''Windows'' else [''ping'', ip, ''-c 1'']
shell_needed = True if operating_sys == ''Windows'' else False
ping_output = subprocess.run(ping_command,shell=shell_needed,stdout=subprocess.PIPE)
success = ping_output.returncode
return True if success == 0 else False
out = ping(nas)
print(out)
Parece bastante simple, pero me dio ajustes. Seguí obteniendo "la operación de socket abierto icmp no permitida" o de lo contrario las soluciones colgarían si el servidor estuviera fuera de línea. Sin embargo, si lo que desea saber es que el servidor está activo y está ejecutando un servidor web en ese servidor, entonces curl hará el trabajo. Si tiene ssh y certificados, entonces ssh y un simple comando serán suficientes. Aquí está el código:
from easyprocess import EasyProcess # as root: pip install EasyProcess
def ping(ip):
ping="ssh %s date;exit"%(ip) # test ssh alive or
ping="curl -IL %s"%(ip) # test if http alive
response=len(EasyProcess(ping).call(timeout=2).stdout)
return response #integer 0 if no response in 2 seconds
Resuelvo esto con:
def ping(self, host):
res = False
ping_param = "-n 1" if system_name().lower() == "windows" else "-c 1"
resultado = os.popen("ping " + ping_param + " " + host).read()
if "TTL=" in resultado:
res = True
return res
"TTL" es la forma de saber si el ping es correcto. Saludos
Si no necesita soportar Windows, aquí hay una forma muy concisa de hacerlo:
import os
hostname = "google.com" #example
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
print hostname, ''is up!''
else:
print hostname, ''is down!''
Esto funciona porque ping devuelve un valor distinto de cero si la conexión falla. (El valor de retorno en realidad difiere según el error de red). También puede cambiar el tiempo de espera del ping (en segundos) usando la opción ''-t''. Tenga en cuenta que esto enviará texto a la consola.
Tenía un requisito similar, así que lo implementé como se muestra a continuación. Está probado en Windows 64 bit y Linux.
import subprocess
def systemCommand(Command):
Output = ""
Error = ""
try:
Output = subprocess.check_output(Command,stderr = subprocess.STDOUT,shell=''True'')
except subprocess.CalledProcessError as e:
#Invalid command raises this exception
Error = e.output
if Output:
Stdout = Output.split("/n")
else:
Stdout = []
if Error:
Stderr = Error.split("/n")
else:
Stderr = []
return (Stdout,Stderr)
#in main
Host = "ip to ping"
NoOfPackets = 2
Timeout = 5000 #in milliseconds
#Command for windows
Command = ''ping -n {0} -w {1} {2}''.format(NoOfPackets,Timeout,Host)
#Command for linux
#Command = ''ping -c {0} -w {1} {2}''.format(NoOfPackets,Timeout,Host)
Stdout,Stderr = systemCommand(Command)
if Stdout:
print("Host [{}] is reachable.".format(Host))
else:
print("Host [{}] is unreachable.".format(Host))
Cuando IP no es alcanzable, subprocess.check_output () genera una excepción. La verificación adicional se puede hacer extrayendo información de la línea de salida ''Paquetes: Enviados = 2, Recibidos = 2, Perdidos = 0 (0% de pérdidas)''.
Terminé encontrando esta pregunta con respecto a un escenario similar. Probé la creación de pirámides pero el ejemplo dado por Naveen no funcionó para mí en Windows bajo Python 2.7.
Un ejemplo que funcionó para mí es:
import pyping
response = pyping.send(''Your IP'')
if response[''ret_code''] == 0:
print("reachable")
else:
print("unreachable")
Una cosa que muchas de las respuestas se pierden es que (al menos en Windows) el comando ping
devuelve 0 (indicando éxito) si recibe la respuesta "host de destino inalcanzable".
Aquí está mi código que verifica si b''TTL=''
está en la respuesta, ya que eso solo está presente cuando el ping llegó al host. Nota: la mayoría de este código se basa en las otras respuestas aquí.
import platform
import subprocess
def ping(ipAddr, timeout=100):
''''''
Send a ping packet to the specified host, using the system ping command.
Accepts ipAddr as string for the ping destination.
Accepts timeout in ms for the ping timeout.
Returns True if ping succeeds otherwise Returns False.
Ping succeeds if it returns 0 and the output includes b''TTL=''
''''''
if platform.system().lower() == ''windows'':
numFlag = ''-n''
else:
numFlag = ''-c''
completedPing = subprocess.run([''ping'', numFlag, ''1'', ''-w'', str(timeout), ipAddr],
stdout=subprocess.PIPE, # Capture standard out
stderr=subprocess.STDOUT) # Capture standard error
# print(completedPing.stdout)
return (completedPing.returncode == 0) and (b''TTL='' in completedPing.stdout)
print(ping(''google.com''))
Nota: Esto captura el resultado en lugar de imprimirlo, por lo que si desea ver el resultado de ping
, deberá imprimir completedPing.stdout
antes de regresar.
Usando Multi-ping ( pip install multiPing
) hice este código simple (¡ simplemente copie y pegue si lo desea! ):
from multiping import MultiPing
def ping(host,n = 0):
if(n>0):
avg = 0
for i in range (n):
avg += ping(host)
avg = avg/n
# Create a MultiPing object to test three hosts / addresses
mp = MultiPing([host])
# Send the pings to those addresses
mp.send()
# With a 1 second timout, wait for responses (may return sooner if all
# results are received).
responses, no_responses = mp.receive(1)
for addr, rtt in responses.items():
RTT = rtt
if no_responses:
# Sending pings once more, but just to those addresses that have not
# responded, yet.
mp.send()
responses, no_responses = mp.receive(1)
RTT = -1
return RTT
Uso:
#Getting the latency average (in seconds) of host ''192.168.0.123'' using 10 samples
ping(''192.168.0.123'',10)
Si quiere una sola muestra, ¡puede ignorar el segundo parámetro " 10
"!
¡Espero eso ayude!
Use esto, ha sido probado en Python 2.7 y funciona bien, devuelve el tiempo de ping en milisegundos si es exitoso y devuelve False on fail.
import platform,subproccess,re
def Ping(hostname,timeout):
if platform.system() == "Windows":
command="ping "+hostname+" -n 1 -w "+str(timeout*1000)
else:
command="ping -i "+str(timeout)+" -c 1 " + hostname
proccess = subprocess.Popen(command, stdout=subprocess.PIPE)
matches=re.match(''.*time=([0-9]+)ms.*'', proccess.stdout.read(),re.DOTALL)
if matches:
return matches.group(1)
else:
return False
Esta función funciona en cualquier sistema operativo (Unix, Linux, OS X y Windows)
Python 2 y Python 3
EDIT 1: Agregó algunos comentarios a la respuesta original.
EDIT 2: Siguiendo una sugerencia de @radato , os.system
fue reemplazado por subprocess.call
.
from platform import system as system_name # Returns the system/OS name
from subprocess import call as system_call # Execute a shell command
def ping(host):
"""
Returns True if host (str) responds to a ping request.
Remember that a host may not respond to a ping (ICMP) request even if the host name is valid.
"""
# Ping command count option as function of OS
param = ''-n'' if system_name().lower()==''windows'' else ''-c''
# Building the command. Ex: "ping -c 1 google.com"
command = [''ping'', param, ''1'', host]
# Pinging
return system_call(command) == 0
El comando es ping
en sistemas Windows y Unix. La opción -n (Windows) o -c (Unix) controla el número de paquetes que en este ejemplo es 1.
platform.system()
devuelve el nombre de la plataforma. Ex. ''Darwin''
en macOS
subprocess.call()
realiza una llamada al sistema. Ex. subprocess.call([''ls'',''-l''])
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import time
6
7 os.system("clear")
8 home_network = "172.16.23."
9 mine = []
10
11 for i in range(1, 256):
12 z = home_network + str(i)
13 result = os.system("ping -c 1 "+ str(z))
14 os.system("clear")
15 if result == 0:
16 mine.append(z)
17
18 for j in mine:
19 print "host ", j ," is up"
Uno simple que acabo de cocinar en un minuto ... usando icmplib necesita privs de raíz, el siguiente funciona bastante bien. HTH
#!/usr/bin/python3
import subprocess as sp
def ipcheck():
status,result = sp.getstatusoutput("ping -c1 -w2 " + str(pop))
if status == 0:
print("System " + str(pop) + " is UP !")
else:
print("System " + str(pop) + " is DOWN !")
pop = input("Enter the ip address: ")
ipcheck()
#!/usr/bin/python3
import subprocess as sp
ip = "192.168.122.60"
status,result = sp.getstatusoutput("ping -c1 -w2 " + ip)
if status == 0:
print("System " + ip + " is UP !")
else:
print("System " + ip + " is DOWN !")
import subprocess
ping_response = subprocess.Popen(["/bin/ping", "-c1", "-w100", "192.168.0.1"], stdout=subprocess.PIPE).stdout.read()