import socket
import tkinter as tk
from tkinter import messagebox
import select

HOST = '192.168.1.1'  # 默认目标IP
PORT = 8001  # 默认目标端口


class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title("TCP客户端")  # 设置窗口标题
        self.pack()

        # 创建IP输入框
        self.host_label = tk.Label(self, text="目标IP:")
        self.host_label.grid(row=0, column=0)
        self.host_entry = tk.Entry(self)
        self.host_entry.insert(0, HOST)
        self.host_entry.grid(row=0, column=1)

        # 创建端口输入框
        self.port_label = tk.Label(self, text="目标端口:")
        self.port_label.grid(row=1, column=0)
        self.port_entry = tk.Entry(self)
        self.port_entry.insert(0, PORT)
        self.port_entry.grid(row=1, column=1)

        # 创建超时时间输入框
        self.timeout_label = tk.Label(self, text="接收超时(ms):")
        self.timeout_label.grid(row=2, column=0)
        self.timeout_entry = tk.Entry(self)
        self.timeout_entry.insert(0, "-1")  # 默认为不等待回复
        self.timeout_entry.grid(row=2, column=1)

        # 创建报文输入框
        self.msg_label = tk.Label(self, text="报文内容:")
        self.msg_label.grid(row=3, column=0)
        self.msg_entry = tk.Entry(self)
        self.msg_entry.grid(row=3, column=1)

        # 创建开始连接按钮
        self.connect_button = tk.Button(self, text="开始连接", command=self.connect)
        self.connect_button.grid(row=4, column=0)

        # 创建中断连接按钮
        self.disconnect_button = tk.Button(self, text="中断连接", state=tk.DISABLED, command=self.disconnect)
        self.disconnect_button.grid(row=4, column=1)

        # 创建发送按钮
        self.send_button = tk.Button(self, text="发送", state=tk.DISABLED, command=self.send_msg)
        self.send_button.grid(row=5, column=1)

        # 保存连接状态
        self.connected = False

        # 设置读取超时时间
        self.timeout = 1.0

    def connect(self):
        # 获取IP和端口
        global HOST, PORT
        HOST = self.host_entry.get()
        PORT = int(self.port_entry.get())

        try:
            # 创建TCP客户端套接字并连接目标主机
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((HOST, PORT))

            # 设置非阻塞式I/O
            self.sock.setblocking(False)

            # 设置连接状态和按钮状态
            self.connected = True
            self.connect_button.config(state=tk.DISABLED)
            self.disconnect_button.config(state=tk.NORMAL)
            self.send_button.config(state=tk.NORMAL)

        except OSError:
            self.show_error("连接错误", "无法连接到目标主机,请检查IP和端口是否正确")

        except Exception as e:
            self.show_error("连接错误", str(e))

    def disconnect(self):
        # 关闭连接和设置状态
        self.sock.close()
        self.connected = False
        self.connect_button.config(state=tk.NORMAL)
        self.disconnect_button.config(state=tk.DISABLED)
        self.send_button.config(state=tk.DISABLED)

    def send_msg(self):
        try:
            # 获取报文内容并将其转换为16进制
            msg = bytearray.fromhex(self.msg_entry.get())

            # 发送报文
            self.sock.sendall(msg)

            # 获取可读取的socket
            rlist, _, _ = select.select([self.sock], [], [], float(self.timeout_entry.get()) / 1000)

            if len(rlist) > 0:
                # 接收响应
                data = self.sock.recv(1024)

                # 将响应数据转换为16进制
                hex_data = data.hex()

                # 弹出消息框显示响应内容
                response = "响应内容:" + hex_data
                messagebox.showinfo(title="回复", message=response)

            elif float(self.timeout_entry.get()) < 0:
                # 不等待响应
                pass

            else:
                self.show_error("接收超时", "等待响应超时,请检查网络连接是否正常")

        except socket.timeout:
            self.show_error("接收超时", "等待响应超时,请检查网络连接是否正常")

        except OSError:
            self.show_error("连接错误", "无法发送数据,请检查连接是否正常")

        except Exception as e:
            self.show_error("发送错误", str(e))

    def show_error(self, title, message):
        # 弹出错误窗口
        messagebox.showerror(title=title, message=message)


# 创建GUI应用程序并运行
root = tk.Tk()
app = Application(master=root)
app.mainloop()