python icmp
时间: 2023-08-25 14:14:57 浏览: 56
以下是一个使用 Python 发送 ICMP 消息的例子,使用 Python 标准库 socket 实现:
```python
import socket
import struct
import select
import time
# 构造 ICMP 报文
def create_packet():
# type 8 表示发送 Echo Request 请求
# code 0 表示无差错
# checksum 先填 0,后面计算
# id 和 sequence number 都随便填一个数字
header = struct.pack("bbHHh", 8, 0, 0, 12345, 1)
data = b"hello, world!"
checksum = calculate_checksum(header + data)
header = struct.pack("bbHHh", 8, 0, checksum, 12345, 1)
packet = header + data
return packet
# 计算校验和
def calculate_checksum(data):
if len(data) % 2 != 0:
data += b"\x00"
checksum = 0
for i in range(0, len(data), 2):
word = (data[i] << 8) + data[i+1]
checksum += word
checksum = (checksum >> 16) + (checksum & 0xffff)
checksum = checksum + (checksum >> 16)
return ~checksum & 0xffff
# 发送 ICMP 报文并等待响应
def ping(destination, timeout=1):
# 创建 socket
icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp"))
icmp_socket.settimeout(timeout)
# 构造 ICMP 报文
packet = create_packet()
# 发送 ICMP 报文
icmp_socket.sendto(packet, (destination, 0))
# 等待响应
start_time = time.time()
while True:
# select 可以等待多个文件描述符就绪
# 第一个参数是需要等待的文件描述符列表,第二个参数是超时时间(单位秒)
ready_to_read, _, _ = select.select([icmp_socket], [], [], max(0, start_time + timeout - time.time()))
if ready_to_read:
# 收到响应
reply_packet, address = icmp_socket.recvfrom(1024)
time_cost = (time.time() - start_time) * 1000
# 解析响应报文
icmp_type, _, checksum, _, sequence = struct.unpack("bbHHh", reply_packet[20:28])
if icmp_type == 0 and checksum == calculate_checksum(reply_packet[20:28]):
print(f"Reply from {address}, time={time_cost:.3f} ms, sequence={sequence}")
return True
else:
# 超时
print("Request timed out.")
return False
# 测试
ping("www.google.com")
```
这个例子中,我们首先构造了一个 ICMP 报文,包含 Echo Request 请求和一些数据。然后,我们使用 socket 发送这个报文,等待响应。在等待响应的过程中,我们使用 select 函数来等待文件描述符就绪,以避免阻塞。如果收到响应,我们解析响应报文并打印出 ICMP 序列号、时间等信息。如果超时没有收到响应,则打印 "Request timed out."。