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

logging.basicConfig(filename='TCPClient.log', level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')

packet_file_path = ''

# 读取文件中的16进制报文
def read_hex_packets(file_path):
    packets = []
    try:
        with open(file_path, "r") as f:
            lines = f.readlines()
            for line in lines:
                # 缩进块要注意缩进的空格数,通常为四个空格
                line = line.strip()
                if not line:
                    continue
                try:
                    packet = bytes.fromhex(line)
                except ValueError:
                    logging.error("无效的报文格式: %s", line)
                    continue
                packets.append(packet)
    except IOError as e:
        logging.error("读取文件 %s 失败: %s", file_path, str(e))
    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())

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

    # 创建TCP客户端socket
    try:
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    except socket.error as e:
        logging.error("创建socket失败: %s", str(e))
        return

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

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

        for i, packet in enumerate(packets):
            # 发送报文
            try:
                client_socket.sendall(packet)
            except socket.error as e:
                logging.error("发送第%d帧报文失败: %s", i+1, str(e))
                continue
            logging.info("发送第%d帧报文: %s", i+1, packet.hex())

            # 等待服务器回传
            if wait_for_response:
                try:
                    response_packet = client_socket.recv(1024)
                    logging.info("收到第%d帧回传报文: %s", i+1, response_packet.hex())
                    response_text.insert(tk.END, response_packet.hex() + "\n")
                except socket.error as e:
                    logging.error("接收第%d帧回传报文失败: %s", i+1, str(e))

            # 等待一定时间再发送下一帧
            if i != len(packets)-1:
                time.sleep(send_interval / 1000)

    except socket.error as e:
        logging.error(str(e))

    finally:
        # 关闭socket连接
        client_socket.close()

# 打开文件对话框
def open_file_dialog():
    global packet_file_path
    packet_file_path = filedialog.askopenfilename(filetypes=(("Text files", "*.txt"),))
    file_path_label.config(text=packet_file_path)

# 创建GUI界面
root = tk.Tk()
root.title("TCP客户端")

# 服务器ip和端口号输入框
server_frame = tk.Frame()
server_frame.pack(side=tk.TOP, padx=10, pady=10)
server_ip_label = tk.Label(server_frame, text="服务器IP: ")
server_ip_label.pack(side=tk.LEFT)
server_ip_entry = tk.Entry(server_frame, width=15)
server_ip_entry.pack(side=tk.LEFT)
server_port_label = tk.Label(server_frame, text="服务器端口号: ")
server_port_label.pack(side=tk.LEFT)
server_port_entry = tk.Entry(server_frame, width=5)
server_port_entry.pack(side=tk.LEFT)

# 选择报文文件和发送间隔输入框
file_frame = tk.Frame()
file_frame.pack(side=tk.TOP, padx=10, pady=10)
open_file_button = tk.Button(file_frame, text="选择报文文件", command=open_file_dialog)
open_file_button.pack(side=tk.LEFT)
file_path_label = tk.Label(file_frame, text="尚未选择文件")
file_path_label.pack(side=tk.LEFT, padx=10)
send_interval_label = tk.Label(file_frame, text="发送间隔(ms): ")
send_interval_label.pack(side=tk.LEFT)
send_interval_entry = tk.Entry(file_frame, width=5)
send_interval_entry.pack(side=tk.LEFT)

# "发送每一帧报文之后都等待服务器回传数据"勾选框
wait_for_response_var = tk.BooleanVar()
wait_for_response_checkbox = tk.Checkbutton(root, text="发送每一帧报文之后都等待服务器回传数据", variable=wait_for_response_var)
wait_for_response_checkbox.pack(side=tk.TOP)

# 发送和接收框
text_frame = tk.Frame()
text_frame.pack(side=tk.TOP, padx=10, pady=10)
text = tk.Text(text_frame, height=10, width=50)
text.pack(side=tk.LEFT)
response_text = tk.Text(text_frame, height=10, width=50)
response_text.pack(side=tk.RIGHT)

# 发送按钮
send_button = tk.Button(root, text="发送", command=send_packets)
send_button.pack(side=tk.BOTTOM, pady=10)

root.mainloop()