Есть ли в Python способ проверить связь с сервером через ICMP и вернуть значение ИСТИНА, если сервер отвечает, или ЛОЖЬ, если ответа нет?
Проверка связи с серверами на Python
Ответы (27)
Эта функция работает в любой ОС (Unix, Linux, macOS и Windows)
Python 2 и Python 3
РЕДАКТИРОВАТЬ:
Автор @radato os.system был заменен на subprocess.call. Это позволяет избежать уязвимости инъекции оболочки в случаях, когда строка вашего имени хоста не может быть проверена.
import platform # For getting the operating system name
import subprocess # For executing 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.
"""
# Option for the number of packets as a function of
param = '-n' if platform.system().lower()=='windows' else '-c'
# Building the command. Ex: "ping -c 1 google.com"
command = ['ping', param, '1', host]
return subprocess.call(command) == 0
Обратите внимание, что, согласно @ikrase в Windows, эта функция по-прежнему будет возвращать True, если вы получите ошибку Destination Host Unreachable.
Объяснение
Команда - это ping как в Windows, так и в Unix-подобных системах.
Параметр -n (Windows) или -c (Unix) контролирует количество пакетов, которое в этом примере было установлено равным 1.
platform.system() возвращает имя платформы. Бывший. 'Darwin' в macOS. subprocess.call() выполняет системный вызов. Бывший. subprocess.call(['ls','-l']).
ping 8.8.8.8 -n 1 3) echo %ERRORLEVEL%. Код: измените последнюю строку кода Python на return system_call(command). При правильном подключении вы получите 0 (ноль). При выключенном модеме вы должны получить код ошибки. Конечно, оба метода должны возвращать один и тот же код ошибки при одинаковых условиях.
- person ePi272314; 12.11.2018
system.call - опечатка и должна быть subprocess.call?
- person ishahak; 07.03.2019
Если вам не нужна поддержка Windows, вот действительно краткий способ сделать это:
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!'
Это работает, потому что ping возвращает ненулевое значение в случае сбоя соединения. (На самом деле возвращаемое значение различается в зависимости от сетевой ошибки.) Вы также можете изменить время ожидания проверки связи (в секундах) с помощью параметра «-t». Обратите внимание, это выведет текст на консоль.
response = os.system("ping -c 1 -w2 " + hostname + " > /dev/null 2>&1")
- person MGP; 14.08.2013
hostname!
- person hek2mgl; 11.05.2015
man ping.
- person Alan Turing; 15.06.2015
hostname от пользователя, он может легко взломать ваш сервер, предоставив вам URL-адрес типа 'google.com; rm -rf /*'. Вместо этого используйте subprocess.run(["ping", "-c", "1", hostname]).returncode.
- person Boris; 26.01.2019
subprocess.run: command = ["ping", "-c", "1", "-w2", host] return subprocess.run(args=command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
- person Ian Colwell; 29.06.2021
Для этого существует модуль под названием pyping. Его можно установить с помощью пипса
pip install pyping
Он довольно прост в использовании, однако при использовании этого модуля вам понадобится root-доступ, поскольку он создает необработанные пакеты под капотом.
import pyping
r = pyping.ping('google.com')
if r.ret_code == 0:
print("Success")
else:
print("Failed with {}".format(r.ret_code))
os.system('ping -c 1 -t 1 hostname'). Кроме того, pyping lib очень проста в использовании по сравнению с использованием библиотеки сокетов TCP / IP. Я написал свою программу ping, используя оба, и pyping, на мой взгляд, намного быстрее и проще в использовании, особенно если кто-то не знаком с использованием библиотеки сокетов TCP / IP.
- person MikeyE; 24.11.2017
pip install ping3
- person beep_check; 03.01.2019
Для python3 существует очень простой и удобный модуль python ping3: (pip install ping3, требуется root strong > привилегии).
from ping3 import ping, verbose_ping
ping('example.com') # Returns delay in seconds.
>>> 0.215697261510079666
Этот модуль также позволяет настраивать некоторые параметры.
Поскольку мне нравится иметь универсальную программу Python для версий 2.7 и 3.x, а также для платформ Linux, Mac OS и Windows, мне пришлось изменить существующие примеры.
# 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"))
False if platform.system().lower()=="windows" else True вы, конечно, можете просто использовать platform.system().lower() != "windows".
- person Frerich Raabe; 13.05.2016
os.name!="nt" тоже не работает? По общему признанию, я не пробовал это со всеми комбинациями версий / платформ!
- person Keeely; 11.01.2017
def ping(host): process = subprocess.Popen(["ping", "-n", "1",host], stdout=subprocess.PIPE, stderr=subprocess.PIPE) streamdata = process.communicate()[0] if 'unreachable' in str(streamdata): return 1 return process.returncode
- person wellspokenman; 19.03.2018
unreachable найден в трубе, не так ли?
- person beeb; 25.05.2018
Программный пинг ICMP сложен из-за повышенных привилегий, необходимых для отправки необработанных пакетов ICMP, а вызов двоичного файла ping уродлив. Для мониторинга сервера вы можете добиться того же результата, используя метод под названием 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
Внутренне это просто устанавливает TCP-соединение с целевым сервером и немедленно разрывает его, измеряя прошедшее время. Эта конкретная реализация немного ограничена тем, что она не обрабатывает закрытые порты, но для ваших собственных серверов она работает довольно хорошо.
Осмотревшись, я закончил писать свой собственный модуль ping, который предназначен для мониторинга большого количества адресов, является асинхронным и не использует много системных ресурсов. Вы можете найти его здесь: https://github.com/romana/multi-ping/ Он лицензирован Apache, поэтому вы можете использовать его в своем проекте любым удобным для вас способом.
Основными причинами для реализации моего собственного являются ограничения других подходов:
- Многие из упомянутых здесь решений требуют выполнения команды exec в утилите командной строки. Это довольно неэффективно и требует больших ресурсов, если вам нужно отслеживать большое количество IP-адресов.
- Другие упоминают некоторые старые модули ping python. Я посмотрел на них и, в конце концов, все они имели ту или иную проблему (например, некорректную установку идентификаторов пакетов) и не обрабатывали пинг большого количества адресов.
Убедитесь, что pyping установлен, или установите его pip install pyping
#!/usr/bin/python
import pyping
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
Моя версия функции ping:
- Работает на Python 3.5 и новее, в Windows и Linux (должно работать на Mac, но не могу его протестировать).
- В Windows возвращает False, если команда ping завершилась неудачно с "Destination Host Unreachable".
- И не показывает никаких выходных данных ни в виде всплывающего окна, ни в командной строке.
import platform, subprocess
def ping(host_or_ip, packets=1, timeout=1000):
''' Calls system "ping" command, returns True if ping succeeds.
Required parameter: host_or_ip (str, address of host to ping)
Optional parameters: packets (int, number of retries), timeout (int, ms to wait for response)
Does not show any output, either as popup window or in command line.
Python 3.5+, Windows and Linux compatible (Mac not tested, should work)
'''
# The ping command is the same for Windows and Linux, except for the "number of packets" flag.
if platform.system().lower() == 'windows':
command = ['ping', '-n', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: capture output, discard error messages, do not show window
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, creationflags=0x08000000)
# 0x0800000 is a windows-only Popen flag to specify that a new process will not create a window.
# On Python 3.7+, you can use a subprocess constant:
# result = subprocess.run(command, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
# On windows 7+, ping returns 0 (ok) when host is not reachable; to be sure host is responding,
# we search the text "TTL=" on the command output. If it's there, the ping really had a response.
return result.returncode == 0 and b'TTL=' in result.stdout
else:
command = ['ping', '-c', str(packets), '-w', str(timeout), host_or_ip]
# run parameters: discard output and error messages
result = subprocess.run(command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return result.returncode == 0
Не стесняйтесь использовать его по своему усмотрению.
Я решаю это с помощью:
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 - это способ узнать, правильно ли выполнен пинг. Салудос
Мое сокращение с использованием идей из ответов в этом сообщении, но только с использованием нового рекомендованного модуля подпроцесса и python3:
import subprocess
import platform
operating_sys = platform.system()
nas = '192.168.0.10'
def ping(ip):
# ping_command = ['ping', ip, '-n', '1'] instead of ping_command = ['ping', ip, '-n 1'] for Windows
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)
True if condition else False для возврата True или False в зависимости от условия. Просто используйте, например, shell_needed = operating_sys == 'Windows' и return success == 0
- person emorris; 13.02.2017
Этот сценарий работает в Windows и должен работать в других операционных системах: он работает в Windows, Debian и macosx, требуется тестирование в 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
В итоге я нашел этот вопрос относительно аналогичного сценария. Я пробовал использовать pyping, но пример, приведенный Naveen, не работал у меня в Windows под Python 2.7.
Пример, который сработал для меня:
import pyping
response = pyping.send('Your IP')
if response['ret_code'] == 0:
print("reachable")
else:
print("unreachable")
pyping не является стандартным модулем. Не могли бы вы дать ссылку?
- person Mawg says reinstate Monica; 22.03.2016
Используя Multi-ping (pip install multiPing), я сделал этот простой код (просто скопируйте и вставьте, если хотите!):
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 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
Использование:
#Getting the latency average (in seconds) of host '192.168.0.123' using 10 samples
ping('192.168.0.123',10)
Если вам нужен единственный образец, второй параметр «10» можно игнорировать!
Надеюсь, это поможет!
Мне нужна была более быстрая проверка связи, и я не хотел использовать какие-либо внешние библиотеки, поэтому решил использовать параллелизм с использованием встроенного asyncio.
Для этого кода требуется python 3.7+, он создан и протестирован только на Linux. Он не будет работать в Windows, но я уверен, что вы можете легко изменить его для работы в Windows.
Я не эксперт в asyncio, но я использовал эту замечательную статью Ускорьте свою программу Python с помощью параллелизма и я придумал эти строки кода. Я постарался сделать его максимально простым, поэтому, скорее всего, вам нужно будет добавить в него больше кода в соответствии с вашими потребностями.
Он не возвращает true или false, я подумал, что было бы удобнее просто заставить его печатать IP, который отвечает на запрос ping. Я думаю, что это довольно быстро, пингует 255 ips почти за 10 секунд.
#!/usr/bin/python3
import asyncio
async def ping(host):
"""
Prints the hosts that respond to ping request
"""
ping_process = await asyncio.create_subprocess_shell("ping -c 1 " + host + " > /dev/null 2>&1")
await ping_process.wait()
if ping_process.returncode == 0:
print(host)
return
async def ping_all():
tasks = []
for i in range(1,255):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
await asyncio.gather(*tasks, return_exceptions = True)
asyncio.run(ping_all())
Пример вывода:
192.168.1.1
192.168.1.3
192.168.1.102
192.168.1.106
192.168.1.6
Обратите внимание, что IP-адреса не в порядке, поскольку IP-адрес печатается, как только он отвечает, поэтому тот, который отвечает первым, печатается первым.
Кажется достаточно простым, но меня не устраивало. Я продолжал получать сообщение «icmp open socket operation not allowed», иначе решения зависли бы, если бы сервер был отключен. Однако если вы хотите знать, что сервер активен и на нем запущен веб-сервер, то curl выполнит свою работу. Если у вас есть ssh и сертификаты, тогда будет достаточно ssh и простой команды. Вот код:
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
У меня было аналогичное требование, поэтому я реализовал его, как показано ниже. Он протестирован на 64-битной Windows и 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))
Когда IP недоступен, subprocess.check_output () вызывает исключение. Дополнительная проверка может быть выполнена путем извлечения информации из выходной строки «Пакеты: отправлено = 2, принято = 2, потеряно = 0 (потеря 0%)».
Вот решение с использованием модуля Python subprocess и инструмента ping CLI, предоставляемого базовой ОС. Проверено на Windows и Linux. Поддержка настройки тайм-аута сети. Не требует прав root (по крайней мере, в Windows и 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().lower()
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
Используйте это, он протестирован на python 2.7 и отлично работает, он возвращает время пинга в миллисекундах в случае успеха и возвращает False в случае неудачи.
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
ТОЛЬКО ДЛЯ WINDOWS - не могу поверить, что никто не взломал Win32_PingStatus. Используя простой запрос WMI, мы бесплатно возвращаем объект, полный действительно подробной информации.
import wmi
# new WMI object
c = wmi.WMI()
# here is where the ping actually is triggered
x = c.Win32_PingStatus(Address='google.com')
# how big is this thing? - 1 element
print 'length x: ' ,len(x)
#lets look at the object 'WMI Object:\n'
print x
#print out the whole returned object
# only x[0] element has values in it
print '\nPrint Whole Object - can directly reference the field names:\n'
for i in x:
print i
#just a single field in the object - Method 1
print 'Method 1 ( i is actually x[0] ) :'
for i in x:
print 'Response:\t', i.ResponseTime, 'ms'
print 'TTL:\t', i.TimeToLive
#or better yet directly access the field you want
print '\npinged ', x[0].ProtocolAddress, ' and got reply in ', x[0].ResponseTime, 'ms'
Я заимствую из других ответов. Попытка упростить и свести к минимуму запросы.
import platform, os
def ping(host):
result = os.popen(' '.join(("ping", ping.param, host))).read()
return 'TTL=' in result
ping.param = "-n 1" if platform.system().lower() == "windows" else "-c 1"
используя пакет сокетов в python3:
import socket
def ping_server(server: str, port: int, timeout=3):
"""ping server"""
try:
socket.setdefaulttimeout(timeout)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
except OSError as error:
return False
else:
s.close()
return True
Пингуйте их все в Windows или Linux, верните отсортированный список. Это гибрид / исправление из ответов @Ahmed Essam и @Arno.
import asyncio
import re
import platform
isWindows = platform.system()
async def ping(host):
cmd = 'ping {} {} 1'.format(host, '-n' if isWindows else '-c')
ping_proc = \
await asyncio.create_subprocess_shell(cmd, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await ping_proc.communicate()
outstr = stdout.decode()
if ping_proc.returncode == 0:
delay = int(re.search(r'(?:time=)([\d]*)', outstr).group(1)) if 'time=' in outstr else -1
if delay >= 0:
# print('{} {}ms'.format(host, delay))
return [host, delay]
return [host, None]
async def ping_all():
tasks = []
for i in range(1, 256):
ip = "192.168.1.{}".format(i)
task = asyncio.ensure_future(ping(ip))
tasks.append(task)
retList = await asyncio.gather(*tasks, return_exceptions=True)
retList = [x for x in retList if x[1] is not None]
retList.sort(key=lambda x: int(x[0].split('.')[-1]))
return retList
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
pingRet = loop.run_until_complete(ping_all())
for ip, d in pingRet:
print('{:<16s} {}ms'.format(ip, d))
Одна вещь, которую упускают из виду многие ответы, заключается в том, что (по крайней мере, в Windows) команда ping возвращает 0 (что означает успех), если она получает ответ «Целевой хост недоступен».
Вот мой код, который проверяет, есть ли b'TTL=' в ответе, поскольку он присутствует только тогда, когда ping достиг хоста. Примечание. Большая часть этого кода основана на других ответах здесь.
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'))
Примечание. Это захватывает вывод, а не печатает его, поэтому, если вы хотите увидеть вывод ping, вам нужно будет распечатать completedPing.stdout перед возвратом.
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"
Простой, который я приготовил за минуту ... использование icmplib требует root-прав, как показано ниже, работает довольно хорошо! HTH
whereis ping, чтобы получить правильный путь.
- person octern; 21.05.2013
ping_response = subprocess.Popen(["ping", hostname, "-n", '1'], stdout=subprocess.PIPE).stdout.read()
- person Victor Lellis; 05.03.2015
"ping -c1 -w100 192.168.0.1".split()
- person xtofl; 26.09.2015
ping_response = subprocess.call(["ping", "-c1", "-w100", "10.0.0.254"], stdout=subprocess.DEVNULL)
- person Dysmas; 09.01.2020
subprocess.call(["ping", "-n", "1", "10.0.0.24"]) Всегда возвращает 0.
- person Dysmas; 09.01.2020