103 lines
2.9 KiB
Python
103 lines
2.9 KiB
Python
import tkinter as tk
|
|
from tkinter import messagebox
|
|
import socket
|
|
import struct
|
|
import re
|
|
import time
|
|
|
|
|
|
# 计算校验和
|
|
def calculate_checksum(data):
|
|
checksum = 0
|
|
n = len(data)
|
|
|
|
# 按 16 位块划分
|
|
for i in range(0, n - 1, 2):
|
|
chunk = (data[i] << 8) + data[i + 1]
|
|
checksum += chunk
|
|
|
|
# 如果长度为奇数,补零
|
|
if n % 2 == 1:
|
|
checksum += data[-1] << 8
|
|
|
|
# 将 32 位总和折叠为 16 位
|
|
checksum = (checksum >> 16) + (checksum & 0xFFFF)
|
|
checksum += (checksum >> 16)
|
|
|
|
# 对总和取反
|
|
return ~checksum & 0xFFFF
|
|
|
|
|
|
# 构造 ICMP 报文
|
|
def construct_icmp():
|
|
# ICMP 报文头部: 类型(8), 代码(0), 校验和(0), 标识符(1), 序列号(1)
|
|
icmp_header = struct.pack('!BBHHH', 8, 0, 0, 1, 1)
|
|
data = b'Ping'
|
|
# 计算校验和
|
|
checksum = calculate_checksum(icmp_header + data)
|
|
# 填充校验和字段
|
|
icmp_header = struct.pack('!BBHHH', 8, 0, checksum, 1, 1)
|
|
return icmp_header + data
|
|
|
|
|
|
# 构造 UDP 报文
|
|
def construct_udp(src_port, dest_port):
|
|
udp_header = struct.pack('!HHHH', src_port, dest_port, 8, 0)
|
|
return udp_header
|
|
|
|
|
|
# 验证输入
|
|
def validate_ip(ip):
|
|
pattern = re.compile(r'^\d{1,3}(\.\d{1,3}){3}$')
|
|
return pattern.match(ip) is not None
|
|
|
|
|
|
# 发送报文
|
|
def send_packet():
|
|
try:
|
|
target_ip = ip_entry.get()
|
|
target_port = int(port_entry.get())
|
|
packet_type = var.get()
|
|
if not validate_ip(target_ip):
|
|
raise ValueError("目标 IP 地址无效")
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW,
|
|
socket.IPPROTO_ICMP if packet_type == "ICMP" else socket.IPPROTO_UDP)
|
|
|
|
if packet_type == "ICMP":
|
|
packet = construct_icmp()
|
|
elif packet_type == "UDP":
|
|
packet = construct_udp(12345, target_port)
|
|
|
|
start_time = time.time()
|
|
sock.sendto(packet, (target_ip, target_port))
|
|
end_time = time.time()
|
|
|
|
result.set(f"报文发送成功!类型: {packet_type}, 往返时间: {end_time - start_time:.2f} 秒")
|
|
except Exception as e:
|
|
messagebox.showerror("错误", f"报文发送失败: {e}")
|
|
|
|
|
|
# GUI 界面设计
|
|
window = tk.Tk()
|
|
window.title("网络通信软件")
|
|
|
|
tk.Label(window, text="目标 IP 地址:").grid(row=0, column=0)
|
|
ip_entry = tk.Entry(window)
|
|
ip_entry.grid(row=0, column=1)
|
|
|
|
tk.Label(window, text="目标端口号:").grid(row=1, column=0)
|
|
port_entry = tk.Entry(window)
|
|
port_entry.grid(row=1, column=1)
|
|
|
|
tk.Label(window, text="报文类型:").grid(row=2, column=0)
|
|
var = tk.StringVar(value="ICMP")
|
|
tk.Radiobutton(window, text="ICMP", variable=var, value="ICMP").grid(row=2, column=1)
|
|
tk.Radiobutton(window, text="UDP", variable=var, value="UDP").grid(row=2, column=2)
|
|
|
|
result = tk.StringVar()
|
|
tk.Label(window, textvariable=result).grid(row=4, column=0, columnspan=3)
|
|
|
|
tk.Button(window, text="发送报文", command=send_packet).grid(row=3, column=1)
|
|
window.mainloop()
|