这是我第一次在这个网站上问问题,尽管我使用了这里的很多信息,所以我可能不是最擅长问这些问题的 不管怎样,我正在尝试制作一个套接字 tkinter 程序,让一个用户输入一条消息并将其发送回每个人。我肯定还没有完成,但我有一个问题,在我连接到服务器并发送消息然后等待消息返回后,程序窗口冻结并停止响应,而不是返回。这很可能是由于 tkinter 无法更新,因为它正在等待套接字消息,这意味着服务器无法发送消息。这是代码:
客户:
# echo-client.py
import socket
import tkinter as tk
from threading import Thread
snd = False
win = tk.Tk()
win.geometry("365x230")
win.title("chat")
mmsg = ""
conc = False
conn = False
HOST = "192.168." # The server's hostname or IP address
PORT = 0 # The port used by 453 server
def savemsg(event=None):
global mmsg
global conc
if conc:
mmsg = msg.get()
msg.delete(0,tk.END)
snd = True
print("test1")
s.sendall(mmsg.encode("utf8"))
print("test2")
data = s.recv(1024)
print("test3")
if data:
msgtxt.insert(0, (f"{data!r}"[2:-1]))
def LoginWindow():
global lw
global HOST
global PORT
global welc
def connect(event=None):
global HOST
global PORT
global welc
global conc
try:
eval(portb.get())
HOST = addb.get()
PORT = eval(portb.get())
if not conc:
try:
s.connect((HOST,PORT))
conn = False
lw.destroy()
conc = True
except ConnectionRefusedError:
welc.config(text="Server is not open")
conn = False
except socket.gaierror:
welc.config(text="Invalid address!")
conn = False
except:
welc.config(text="Invalid port!")
try:
lw.destroy()
except NameError:
pass
lw = tk.Toplevel()
lw.geometry("300x250")
lw.title("connect")
welc = tk.Label(lw, text="Connect to a server", font=("Arial", 20))
txtf = tk.Frame(lw, height=3)
inputf = tk.Frame(lw, height=3)
addt = tk.Label(txtf, text="address:", height=1, width=30)
portt = tk.Label(txtf, text="port:", height=1, width=16)
addb = tk.Entry(inputf, width=30)
portb = tk.Entry(inputf, width=16)
connbtn = tk.Button(lw, text="Connect", height=1, width=6, command=connect)
welc.pack(side="top", expand=True)
txtf.pack(side="top", expand=True, fill="x")
inputf.pack(side="top", expand=True, fill="x")
addt.pack(side="left", expand=True)
portt.pack(side="right", expand=True)
addb.pack(side="left", expand=True)
portb.pack(side="right", expand=True)
connbtn.pack(side="bottom", expand=True)
addb.insert(0, HOST)
portb.insert(0, str(PORT))
chtxt = tk.Label(text="Chat on socket!", width=15, height=5)
sendframe = tk.Frame(win, height=3, width=10)
sndbtn = tk.Button(sendframe, text="Send!", width=10, height=1)
msg = tk.Entry(sendframe, width=50)
msgtxt = tk.Listbox(width=25, height=7)
scrl = tk.Scrollbar(win, command=msgtxt.yview)
cncb = tk.Button(text="connect", width=6, height=1)
sendframe.pack(side="bottom", expand=True)
chtxt.pack(side="top", expand=True)
cncb.pack(side="top", expand=True)
scrl.pack(side="right", expand=True, anchor="e", fill="y")
msgtxt.pack(expand=True, side="left", anchor="e")
sndbtn.pack(side="right", expand=True)
msg.pack(side="left", expand=True)
msgtxt.config(yscrollcommand=scrl.set)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cncb.config(command=LoginWindow)
sndbtn.config(command=savemsg)
win.bind("<Return>", savemsg)
snd = False
def upd():
global snd
while True:
try:
if snd == True:
s.sendall(mmsg.encode("utf8"))
print(mmsg)
snd = False
except UnboundLocalError:
snd = bool
if snd == True:
s.sendall(mmsg.encode("utf8"))
print(mmsg)
snd = False
def func2():
global conc
while True:
if conc:
data = s.recv(1024)
if data:
msgtxt.insert(1, (f"{data!r}"[2:-1]))
thread = Thread(target = func2, daemon=True)
thread.start()
win.mainloop()
服务器:
# echo-server.py
import socket
from threading import Thread
connections = []
def gethighest(nums=[]):
h = 0
for i in nums:
if i > h:
h = i
return h
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
print("current ip is ", socket.gethostname())
HOST = input("address: \n")
PORT = int(input("port: \n")) # Port to listen on (non-privileged ports are > 1023)
try:
s.bind((HOST, PORT))
print("Server opened")
break
except:
print("invalid!")
def connecc(conn, addr):
with conn:
print(f"Connected by {addr}")
sendtoall("user connected".encode("utf-8"))
while True:
try:
data = conn.recv(1024)
if data:
print(data)
sendtoall(data)
except ConnectionError:
print("user disconnnected")
break
def sendtoall(message):
global connections
for c in connections:
c[0].sendall(message)
print("sent")
while True:
s.listen()
conn, addr = s.accept()
connections.append([conn, addr, Thread(target=connecc, daemon=True, args=(conn, addr))])
connections[len(connections)-1][2].start()
消息应该在客户端上接收回来,但客户端可能因服务器代码编写不正确或无法发送而挂起
您似乎面临这样的问题:发送消息后客户端的 GUI 冻结,可能是由于等待服务器的响应。这种冻结可能是由于客户端的代码结构和缺乏处理套接字通信的线程造成的。
为了解决这个问题,您可以修改客户端的代码以使用线程从服务器发送和接收消息。这样,GUI 在等待响应时就不会冻结。以下是如何构建代码的基本概述:
以下是如何修改客户端代码的简化示例:
import socket
import tkinter as tk
from threading import Thread
# Global variables
HOST = "192.168."
PORT = 0
s = None
def send_message(message):
global s
try:
s.sendall(message.encode("utf8"))
except Exception as e:
print("Error:", e)
def receive_messages():
global s
while True:
try:
data = s.recv(1024)
if data:
# Update GUI with received message
msgtxt.insert(tk.END, data.decode("utf-8"))
except Exception as e:
print("Error:", e)
break
def savemsg(event=None):
# Function to send message from GUI
message = msg.get()
send_message(message)
msg.delete(0, tk.END)
# GUI setup
win = tk.Tk()
# ... (GUI setup code)
# Connect to server function
def connect():
global s
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
# Start a thread to receive messages from the server
receive_thread = Thread(target=receive_messages, daemon=True)
receive_thread.start()
except Exception as e:
print("Error:", e)
# Button to connect to server
cncb = tk.Button(text="Connect", width=6, height=1, command=connect)
# ... (more GUI code)
# Start GUI main loop
win.mainloop()
这只是一个演示该想法的基本示例。您需要将其与现有代码集成并适当处理错误。此外,请记住在关闭应用程序时正确处理关闭套接字连接。