在Python中,是否有一种方法可以通过ICMP来ping服务器,如果服务器响应则返回TRUE,如果没有响应则返回FALSE ?


当前回答

很多答案都忽略了一点(至少在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。

其他回答

如果你不需要支持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'选项更改ping超时(以秒为单位)。注意,这将向控制台输出文本。

我需要一个更快的ping扫描,我不想使用任何外部库,所以我决定使用内置的asyncio来实现并发。

此代码需要python 3.7+,仅在Linux上制作和测试。它不能在Windows上工作,但我相信你可以很容易地将其更改为在Windows上工作。

我不是asyncio方面的专家,但我使用了这篇很棒的文章,用并发性加速你的Python程序,我想出了这些代码行。我试图使它尽可能简单,所以很可能您需要添加更多的代码来满足您的需求。

它不会返回true或false,我认为让它打印响应ping请求的IP会更方便。我认为这是相当快的,在近10秒内ping 255个ip。

#!/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 ping很复杂,因为发送原始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连接,并立即丢弃它,测量所消耗的时间。这个特殊的实现有点局限,因为它不能处理封闭的端口,但对于您自己的服务器来说,它工作得很好。

使用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

使用这个,它在python 2.7上测试过,工作很好,如果成功,它返回以毫秒为单位的ping时间,失败时返回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