在Python中对服务器进行ping测试

265
在Python中,是否有一种通过ICMP对服务器进行ping并在服务器响应时返回TRUE,或者在无响应时返回FALSE的方法?

33个回答

12
#!/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()

2
这段代码可能有答案,但是加上一些注释或解释你的代码如何解决问题会更有帮助。 - skrrgwasme

8
我用以下方式解决了这个问题:
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"是判断ping是否正确的方法。 问候。

没有问题,有目标主机不可达错误 - 请参见@ikrase上面的评论? - Sany

8

如果您的服务器不支持 ICMP(防火墙可能会阻止它),那么它很可能仍然在 TCP 端口上提供服务。在这种情况下,您可以执行一个独立于平台且不需要安装附加 Python 模块的 TCP ping1 操作:

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 ping并不存在,因为ping使用的是ISO/OSI第3层的ICMP。而TCP ping则是在ISO/OSI第4层执行的。它只是以最基本的方式尝试连接到TCP端口,不传输任何数据,并在连接后立即关闭连接。


6

确保已经安装pyping或者安装它 pip install pyping

#!/usr/bin/python
import pyping

response = pyping.ping('Your IP')

if response.ret_code == 0:
    print("reachable")
else:
    print("unreachable")

1
谢谢!不过,我需要以 root 用户身份运行此代码才能使其正常工作。 - Thomas
2
Pyping的GitHub页面已不存在,而PyPI软件包自2016年以来未经更新。 - Stevoisiak
1
我得到了以下错误: import pyping Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/dist-packages/pyping/init.py", line 3, in <module> from core import * ModuleNotFoundError: 找不到名为'core'的模块 - Clock ZHONG

5

借鉴了这篇文章中的一些想法,但只使用了较新的推荐subprocess模块和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)

4
根据条件返回True或False时,您无需使用True if condition else False语句。只需像这样使用shell_needed = operating_sys == 'Windows'return success == 0即可。 - emorris

5
#!/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 !")

4

这个脚本可以在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

很好的答案。这里不需要管理员权限来操作Windows。 - mountainclimber11
1
我无论输入正确或错误的IP地址,都会收到True。 - joash
这肯定行不通。在Windows上无论如何都只会返回“true”。 - MKANET

4
在Linux上,可以创建ICMP数据报(非原始的)套接字而无需以root身份运行(或具有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

尽管其他的答案中提到的许多包也可以使用。

3

使用 Multi-pingpip 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" 可以忽略不计!
希望能对你有所帮助!

5
很棒的库,但需要 root 权限。 - Craynic Cai

2

我有类似的需求,所以我按照下面的方法实现了它。它已经在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%丢失)”中提取信息来进行额外的验证。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接