Python实现Ping程序实验
Ping是一种常见的网络工具,用于测试网络连接的可用性和延迟。在本文中,我们将介绍如何使用Python语言实现一个Ping程序,并通过代码示例演示其使用方式。
什么是Ping?
Ping是一种基于Internet控制报文协议(ICMP)的网络工具。它发送一个ICMP Echo Request消息到目标主机,并等待目标主机返回ICMP Echo Reply消息。通过测量往返时间(RTT),Ping可以估计目标主机的连接质量和延迟。
实现Ping程序
实现思路
要实现一个Ping程序,我们需要完成以下步骤:
- 构建ICMP Echo Request消息
- 发送该消息到目标主机
- 等待目标主机返回ICMP Echo Reply消息
- 计算往返时间(RTT)
代码示例
下面是一个使用Python实现Ping程序的代码示例:
import os
import platform
import struct
import select
import socket
import time
ICMP_ECHO_REQUEST = 8 # ICMP Echo Request类型
def calculate_checksum(source_string):
"""
计算校验和
"""
sum = 0
countTo = (len(source_string) / 2) * 2
count = 0
while count < countTo:
thisVal = ord(source_string[count + 1]) * 256 + ord(source_string[count])
sum = sum + thisVal
sum = sum & 0xffffffff
count = count + 2
if countTo < len(source_string):
sum = sum + ord(source_string[len(source_string) - 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 create_packet():
"""
创建ICMP Echo Request消息
"""
# Header部分,共8字节
icmp_type = ICMP_ECHO_REQUEST
icmp_code = 0
icmp_checksum = 0
icmp_identifier = os.getpid()
icmp_sequence = 1
header = struct.pack("!BBHHH", icmp_type, icmp_code, icmp_checksum, icmp_identifier, icmp_sequence)
# Data部分,共56字节
data = "Ping" * 13
# 计算校验和
icmp_checksum = calculate_checksum(header + data)
# 重新构造ICMP Echo Request消息
packet = struct.pack("!BBHHH", icmp_type, icmp_code, icmp_checksum, icmp_identifier, icmp_sequence) + data
return packet
def send_ping(destination, timeout):
"""
发送Ping消息并等待响应
"""
try:
# 创建socket
icmp = socket.getprotobyname("icmp")
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
# 设置超时时间
sock.settimeout(timeout)
# 构建ICMP Echo Request消息
packet = create_packet()
# 发送消息
sock.sendto(packet, (destination, 0))
# 记录发送时间
start_time = time.time()
# 等待响应
ready, _, _ = select.select([sock], [], [], timeout)
# 计算往返时间
end_time = time.time()
rtt = (end_time - start_time) * 1000
if ready:
data, addr = sock.recvfrom(1024)
return rtt
else:
return None
except socket.gaierror:
print("Hostname could not be resolved.")
except socket.error:
print("Error occurred while creating socket.")
def ping(destination, count, timeout):
"""
发送多个Ping消息并计算平均往返时间
"""
total_rtt = 0
lost_count = 0
for i in range(count):
rtt = send_ping(destination, timeout)
if rtt is None:
lost_count += 1
else:
total_rtt += rtt
print(f"Reply from {destination}: time={rtt}ms")
print(f"\nPing statistics for {destination}:")
print(f"Packets: Sent = {count}, Received = {count - lost_count}, Lost = {lost_count} ({lost_count / count * 100}% loss)")
if count - lost_count > 0:
print(f"Approximate round trip times in milli-seconds:\n"
f"Minimum = {min_r