在Python中,是否有一种方法可以通过ICMP来ping服务器,如果服务器响应则返回TRUE,如果没有响应则返回FALSE ?
当前回答
在linux上,可以创建ICMP数据报(不是原始)套接字,而不需要root(或setuid或CAP_NET_RAW): https://unix.stackexchange.com/a/592914。最后我得到了
$ 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
虽然这里其他答案建议的许多软件包也可以工作
其他回答
我在类似的情况下找到了这个问题。我尝试了pyping,但Naveen给出的例子在Python 2.7下的Windows中对我不起作用。
一个对我有用的例子是:
import pyping
response = pyping.send('Your IP')
if response['ret_code'] == 0:
print("reachable")
else:
print("unreachable")
这个脚本适用于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
我的版本的ping函数:
适用于Python 3.5及更高版本,适用于Windows和Linux。 在Windows上,如果ping命令失败且“目标主机不可达”,则返回False。 并且不显示任何输出,无论是弹出窗口还是命令行。
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
'''
# 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
你想怎么用就怎么用。
在linux上,可以创建ICMP数据报(不是原始)套接字,而不需要root(或setuid或CAP_NET_RAW): https://unix.stackexchange.com/a/592914。最后我得到了
$ 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
虽然这里其他答案建议的许多软件包也可以工作
我使用这篇文章中回答的想法,但只使用更新的推荐子进程模块和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)
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录