import socket
import threading
import tkinter as tk
from tkinter import filedialog

# 读取文件中的16进制报文
def read_hex_packets(file_path):
    with open(file_path, “r”) as f:
        lines = f.readlines()
        packets = []
        for line in lines:
            # 去除行末的换行符和空格
            line = line.strip()
            # 将16进制字符串转换为字节数组
            packet = bytes.fromhex(line)
            packets.append(packet)
        return packets

# 发送报文并打印发送和接收的报文
def send_packets():
    # 获取输入的服务器ip和端口号
    server_ip = server_ip_entry.get()
    server_port = int(server_port_entry.get())

    # 获取是否开启"发送每一帧报文之后都等待服务器回传数据"功能的勾选状态
    wait_for_response = wait_for_response_var.get()

    # 获取报文发送间隔
    send_interval = int(send_interval_entry.get())

    # 打开文件选择对话框，选择报文文件
    file_path = filedialog.askopenfilename(initialdir=“./”, title=“选择报文文件”, filetypes=((“Text Files”, “.txt”), (“All Files”, “.“)))

    # 读取16进制报文
    packets = read_hex_packets(file_path)

    # 创建TCP客户端socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 连接服务器
    client_socket.connect((server_ip, server_port))

    # 清空发送和接收框
    text.delete(1.0, tk.END)

    # 发送报文
    for packet in packets:
        # 发送一帧报文
        client_socket.send(packet)
        # 输出发送的报文
        text.insert(tk.END, “发送报文:” + packet.hex() + “\n”)
        text.see(tk.END)

        # 如果勾选了"发送每一帧报文之后都等待服务器回传数据"功能,则等待回传
        if wait_for_response:
            # 接收服务器回传的数据
            recv_data = client_socket.recv(1024)
            # 输出接收的报文
            text.insert(tk.END, “接收报文:” + recv_data.hex() + “\n”)
            text.see(tk.END)

        # 延时发送下一帧报文
        time.sleep(send_interval / 1000)

    # 关闭socket
    client_socket.close()

# 创建主窗口
root = tk.Tk()
root.title(“TCP Client”)

# 设置窗口大小
root.geometry(“600x500”)

# 创建服务器输入框及标签
server_ip_label = tk.Label(root, text=“服务器IP:”)
server_ip_label.pack(side=tk.TOP, padx=10, pady=10)

server_ip_var = tk.StringVar()
server_ip_entry = tk.Entry(root, textvariable=server_ip_var, justify=“center”)
server_ip_entry.pack(side=tk.TOP, padx=10, pady=5)
server_ip_entry.focus()

server_port_label = tk.Label(root, text=“服务器端口:”)
server_port_label.pack(side=tk.TOP, padx=10)

server_port_var = tk.StringVar()
server_port_entry = tk.Entry(root, textvariable=server_port_var, justify=“center”)
server_port_entry.pack(side=tk.TOP, padx=10, pady=5)

# 创建选择是否等待回传的复选框
wait_for_response_var = tk.BooleanVar()
wait_for_response_check = tk.Checkbutton(root, text=“发送每一帧报文之后都等待服务器回传数据”, variable=wait_for_response_var)
wait_for_response_check.pack(side=tk.TOP, padx=10, pady=5)

# 创建报文发送间隔标签和输入框
send_interval_label = tk.Label(root, text=“报文发送间隔(毫秒):”)
send_interval_label.pack(side=tk.TOP, padx=10)

send_interval_var = tk.StringVar(value=“100”)
send_interval_entry = tk.Entry(root, textvariable=send_interval_var, justify=“center”)
send_interval_entry.pack(side=tk.TOP, padx=10, pady=5)

# 创建发送按钮和导入按钮
send_btn = tk.Button(root, text=“发送报文”, command=lambda: threading.Thread(target=send_packets).start())
send_btn.pack(side=tk.BOTTOM, padx=10, pady=10)

def import_packets():
    # 打开文件选择对话框，选择报文文件
    file_path = filedialog.askopenfilename(initialdir=”./", title=“选择报文文件”, filetypes=((“Text Files”, “.txt”), (“All Files”, ".”)))

    # 如果成功选择了文件
    if file_path:
        # 读取16进制报文
        packets = read_hex_packets(file_path)

        # 将16进制报文显示在发送和接收框中
        text.delete(1.0, tk.END)
        for packet in packets:
            text.insert(tk.END, “发送报文:” + packet.hex() + “\n”)
        text.see(tk.END)

import_btn = tk.Button(root, text="导入报文文件