📜  python ping ip地址 - Python(1)

📅  最后修改于: 2023-12-03 15:18:58.301000             🧑  作者: Mango

Python Ping IP地址

Ping是一种网络工具,用于测试网络连接。它发送一个小的数据包到网络上的另一台计算机上,并等待接收响应。在Python中,可以使用标准库中的socket和subprocess模块实现ping功能。

使用socket模块进行ping

使用socket模块进行ping的步骤如下:

  1. 创建一个ICMP套接字(raw socket)。
  2. 发送一个ICMP Echo请求,并设置一个计时器。
  3. 等待接收ICMP Echo响应。
  4. 计算并返回延迟时间(ping时间)。

下面是一个例子:

import socket
import os
import struct
import time

def checksum(packet):
    '''计算ICMP包的校验和'''
    sum = 0
    countTo = (len(packet) // 2) * 2
    count = 0
    while count < countTo:
        thisVal = ord(packet[count + 1]) * 256 + ord(packet[count])
        sum = sum + thisVal
        sum = sum & 0xffffffff
        count = count + 2
    if countTo < len(packet):
        sum = sum + ord(packet[len(packet) - 1])
        sum = sum & 0xffffffff
    sum = (sum >> 16) + (sum & 0xffff)
    sum = sum + (sum >> 16)
    answer = ~sum
    answer = answer & 0xffff
    answer = answer >> 8 | (answer << 8 & 0xff00)
    return answer

def ping(host, count=4, timeout=2):
    '''ping主机,返回每个ICMP包的延迟时间(单位:秒)'''
    delay_sum = 0
    delay_count = 0

    # 创建ICMP套接字
    icmp = socket.getprotobyname('icmp')
    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)

    # 设置超时(秒)
    sock.settimeout(timeout)

    # 每个包的大小(字节)
    packet_size = 56

    # 发送指定数量的包
    for i in range(count):
        # 构造ICMP包(Echo请求)
        packet_id = os.getpid() & 0xFFFF
        packet_checksum = 0
        packet_data = b'Q'*packet_size
        packet_header = struct.pack('BBHHH', 8, 0, packet_checksum, packet_id, i)
        packet_checksum = checksum(packet_header + packet_data)
        packet_header = struct.pack('BBHHH', 8, 0, packet_checksum, packet_id, i)
        packet = packet_header + packet_data

        try:
            # 记录发送时间
            send_time = time.time()

            # 发送ICMP包并等待响应
            sock.sendto(packet, (host, 1))
            reply, addr = sock.recvfrom(1024)

            # 记录接收时间
            recv_time = time.time()

            # 计算延迟时间
            delay = (recv_time - send_time) * 1000

            # 输出结果
            print('Reply from %s: bytes=%d time=%.1fms' % (addr[0], len(packet), delay))

            # 统计延迟时间
            delay_sum += delay
            delay_count += 1

        except socket.timeout:
            # 输出超时结果
            print('Request timeout')

    # 关闭套接字
    sock.close()

    # 返回平均延迟时间
    return delay_sum / delay_count if delay_count else None

使用方法如下:

delay = ping('192.168.0.1', count=4, timeout=2)
if delay is not None:
    print('Average delay: %.1fms' % delay)
else:
    print('Ping failed')

此处将ping次数设置为4次,并设置超时间为2秒。如果ping成功,会返回每个ICMP包的延迟时间的平均值(单位:毫秒);如果ping失败,会返回None。

使用subprocess模块进行ping

使用subprocess模块进行ping的方法比较简单,只需调用操作系统的ping命令即可。下面是一个例子:

import subprocess

def ping(host, count=4, timeout=2):
    '''ping主机,返回是否ping通'''
    cmd = ['ping', '-c', str(count), '-W', str(timeout), host]
    try:
        # 运行ping命令并等待返回值
        output = subprocess.check_output(cmd)
        return True
    except subprocess.CalledProcessError:
        return False

使用方法同上,只是返回的不是延迟时间,而是是否ping通。如果ping通,返回True;否则返回False。

总结

至此,我们分别介绍了使用socket和subprocess模块进行ping的方法。两种方法各有优劣,需要根据实际情况选择。无论哪种方法,都需要进行错误处理和超时设置,以保证程序的健壮性。