Пинг серверы в Python
Есть ли в Python способ пропинговать сервер через ICMP и возвращать TRUE, если сервер отвечает, или FALSE, если ответа нет?
34 ответа
Если вам не нужна поддержка 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'. Обратите внимание, это выведет текст на консоль.
Эта функция работает в любой ОС (Unix, Linux, macOS и Windows)
Python 2 и Python 3
РЕДАКТИРОВАТЬ 1: Добавлены некоторые комментарии к оригинальному ответу.
РЕДАКТИРОВАТЬ 2: После предложения radato, os.system
был заменен 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
Команда ping
как в Windows, так и в Unix-подобных системах. Опция -n (Windows) или -c (Unix) контролирует количество пакетов, которое в этом примере равно 1.
platform.system()
возвращает имя платформы Ex. 'Darwin'
в macOSsubprocess.call()
выполняет системный вызов. Ex. subprocess.call(['ls','-l'])
Существует модуль, называемый 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))
Мне понравился ping3 https://github.com/kyan001/ping3 Очень просто и удобно!
from ping3 import ping, verbose_ping
ping('example.com') # Returns delay in seconds.
>>>0.215697261510079666
import subprocess
ping_response = subprocess.Popen(["/bin/ping", "-c1", "-w100", "192.168.0.1"], stdout=subprocess.PIPE).stdout.read()
используя пакет сокетов в 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
Программный пинг 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-соединение с целевым сервером и немедленно сбрасывает его, измеряя прошедшее время. Эта конкретная реализация немного ограничена в том, что она не обрабатывает закрытые порты, но для ваших собственных серверов она работает довольно хорошо.
Поскольку мне нравится, что моя программа 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"))
Моя версия функции ping:
- Работает на Python 3.5 и более поздних версиях, в Windows и Linux (должен работать на Mac, но не может его протестировать).
- В Windows возвращает значение False, если команда ping завершается с ошибкой "Целевой хост недоступен".
- И не показывает никакого вывода, ни в виде всплывающего окна, ни в командной строке.
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
Не стесняйтесь использовать его, как вы будете.
Посмотрев вокруг, я написал свой собственный модуль ping, который предназначен для мониторинга большого количества адресов, является асинхронным и не использует много системных ресурсов. Вы можете найти его здесь: https://github.com/romana/multi-ping/ Он лицензирован Apache, поэтому вы можете использовать его в своем проекте так, как считаете нужным.
Основными причинами реализации моих собственных являются ограничения других подходов:
- Многие из упомянутых здесь решений требуют exec для утилиты командной строки. Это довольно неэффективно и требует много ресурсов, если вам нужно отслеживать большое количество IP-адресов.
- Другие упоминают некоторые старые модули ping для Python. Я посмотрел на них, и, в конце концов, у них у всех была та или иная проблема (например, неправильная установка идентификаторов пакетов), и они не обрабатывали пинг большого количества адресов.
#!/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()
Я решаю это с помощью:
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" - это способ узнать, правильно ли выполнен пинг. Saludos
Если ваш сервер не поддерживает ICMP (брандмауэр может его заблокировать), он, скорее всего, все еще предлагает услугу на TCP-порту. В этом случае вы можете выполнить TCP ping1 (независимо от платформы и без установки дополнительных модулей Python) следующим образом:
import socket
def isReachable(ipOrName, port, timeout=2):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
try:
s.connect((ipOrName, int(port)))
s.shutdown(socket.SHUT_RDWR)
return True
except:
return False
finally:
s.close()
Код взят и лишь немного изменен отсюда .
1 Проверка связи TCP на самом деле не существует, так как проверка связи выполняется с помощью ICMP на уровне 3 ISO/OSI. Проверка связи TCP выполняется на уровне 4 ISO/OSI. он не передает никаких данных, а закрывает соединение сразу после соединения.
Убедитесь, что установлен pyping или установите его pip install pyping
#!/usr/bin/python
import pyping
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
Мое сокращение - использование идей из ответов в этом посте, но только с использованием более нового рекомендуемого модуля подпроцесса и 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)
#!/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 !")
Этот скрипт работает в 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
в Linux можно создавать сокеты для датаграмм ICMP (не сырые), не будучи root (или setuid, или
CAP_NET_RAW
): /questions/3634099/naskolko-ploh-etot-kod/3634107#3634107. Я закончил с
$ id
uid=1000(raylu) gid=1000(raylu) [...]
$ sudo sysctl net.ipv4.ping_group_range='1000 1000'
import socket
import struct
import time
def main():
ping('192.168.1.10')
def ping(destination):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.getprotobyname('icmp'))
sock.settimeout(10.0)
start_time = time.time_ns() # python 3.7+ only
payload = struct.pack('L', start_time)
sock.sendto(encode(payload), (destination, 0))
while (time.time_ns() - start_time) // 1_000_000_000 < 10:
try:
data, source = sock.recvfrom(256)
except socket.timeout:
print('timed out')
return
message_type, message_code, check, identifier, sequence_number = struct.unpack('bbHHh', data[:8])
if source == (destination, 0) and message_type == ICMP.ECHO_REPLY and data[8:] == payload:
print((time.time_ns() - start_time) // 1_000_000, 'ms')
break
else:
print('got unexpected packet from %s:' % source[0], message_type, data[8:])
else:
print('timed out')
def encode(payload: bytes):
# calculate checksum with check set to 0
checksum = calc_checksum(icmp_header(ICMP.ECHO_REQUEST, 0, 0, 1, 1) + payload)
# craft the packet again with the checksum set
return icmp_header(ICMP.ECHO_REQUEST, 0, checksum, 1, 1) + payload
def icmp_header(message_type, message_code, check, identifier, sequence_number) -> bytes:
return struct.pack('bbHHh', message_type, message_code, check, identifier, sequence_number)
def calc_checksum(data: bytes) -> int:
'''RFC 1071'''
# code stolen from https://github.com/alessandromaggio/pythonping/blob/a59ce65a/pythonping/icmp.py#L8
'''
MIT License
Copyright (c) 2018 Alessandro Maggio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
'''
subtotal = 0
for i in range(0, len(data)-1, 2):
subtotal += (data[i] << 8) + data[i+1]
if len(data) % 2:
subtotal += (data[len(data)-1] << 8)
while subtotal >> 16:
subtotal = (subtotal & 0xFFFF) + (subtotal >> 16)
check = ~subtotal
return ((check << 8) & 0xFF00) | ((check >> 8) & 0x00FF)
class ICMP:
ECHO_REPLY = 0
ECHO_REQUEST = 8
хотя многие из пакетов, предложенных здесь другими ответами, тоже будут работать
Использование 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
"можно игнорировать!
Надеюсь, поможет!
Я закончил тем, что нашел этот вопрос относительно похожего сценария. Я попробовал pyping, но пример, данный Naveen, не работал для меня в Windows под Python 2.7.
Пример, который работал для меня:
import pyping
response = pyping.send('Your IP')
if response['ret_code'] == 0:
print("reachable")
else:
print("unreachable")
Мне нужна была более быстрая проверка связи, и я не хотел использовать какие-либо внешние библиотеки, поэтому решил использовать параллелизм с использованием встроенных 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 запрещена", иначе решения зависали бы, если бы сервер был отключен. Если, однако, вы хотите знать, что сервер активен и на этом сервере запущен веб-сервер, то 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 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
import os #to get clear screen
import subprocess as sp #to get system ping
os.system("clear") #clear screen
print('Wait or Press Ctrl+Z to Terminate\n') #notice to terminate or wait
for i in range(255): #0 to 255 loop
ip='192.168.1.'+str(i) #concatenating str and int
s,r=sp.getstatusoutput("ping -c1 -w2 " + ip) #ping and store status in s
if s==0: #if status is 0 equal to pass
print(ip+" is UP ✓ ") #output
else: #if status is not 0 equal to fail
pass #skip and try next ip from loop
Единственное удовлетворительное решение, которое я придумал на полпути, это следующее:
from tcppinglib import tcpping
tcpping('example.com', 443, 1, 1).is_alive
Работает под Windows и Linux с использованием непривилегированных учетных записей через простые сокеты.
Судя по всему, также поддерживается асинхронный/множественный «пинг».
Вот решение с использованием 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
Я беру заимствования из других ответов. Попытка упростить и минимизировать запросы.
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"
ТОЛЬКО для 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'
Мой собственный метод, который сочетает в себе несколько ответов выше:
def ping(host, show_log=False, package_count=1):
ping.param = "-n" if platform.system().lower() == 'windows' else "-c"
result = subprocess.run(['ping', ping.param, str(package_count), host],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output = result.stdout
if show_log:
print('return code: ', result.returncode)
print(output.decode("utf-8"))
return result.returncode == 0 and (b'TTL=' in output or b'ttl=' in output)
Протестировано на OSX Monterey.