我正在尝试使用Tkinter和套接字创建聊天服务器,但是大约50%的时间在尝试关闭客户端时出现ConnectionResetError。但是,这不会发生,因为我已经授权使用一个协议来安全处理“退出”事件并关闭套接字,但是服务器仍然显示错误。我该如何解决?
该错误似乎非常奇怪,因为它有时仅出现并且有时可以正常工作,并且服务器显示“客户端已断开连接”消息,指出客户端已安全断开连接,而其他时候它只是由于ConnectionResetError崩溃而崩溃。
服务器:
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
from collections import OrderedDict
import time
def accept_incoming_connections():
while True:
client, client_address = server.accept()
addresses[client] = client_address
Thread(target=handle_client, args=(client,)).start()
def handle_client(client):
name = client.recv(buffer).decode("utf8")
welcome = 'Welcome to the server %s! Type quit to exit :)' % name
add=client.getpeername()
print(add[0]+':'+str(add[1]),'has joined with username '+name)
clients[client] = name
client.send(bytes(welcome, "utf8"))
usrList=','.join(clients.values())
msg = usrList+" %s has joined the chat! " % name
broadcast(bytes(msg, "utf8"))
while True:
msg = client.recv(buffer)
if msg != bytes("quit", "utf8"):
broadcast(msg, name+": ")
else:
client.send(bytes("quit", "utf8"))
client.close()
del clients[client]
usrList=','.join(clients.values())
broadcast(bytes(usrList+" %s has disconnected! " % name, "utf8"))
print(add[0]+':'+str(add[1])+'('+name+')','has disconnected')
break
def broadcast(msg, prefix=""):
for sock in clients:
sock.send(bytes(prefix, "utf8")+msg)
clients = OrderedDict()
addresses = {}
host = ''
port = 33000
buffer = 1024
address = (host, port)
server = socket(AF_INET, SOCK_STREAM)
server.bind(address)
server.listen(5)
print("Waiting for connection...")
accept_thread = Thread(target=accept_incoming_connections)
accept_thread.start()
accept_thread.join()
server.close()
客户:
from socket import AF_INET, socket, SOCK_STREAM
import socket as so
from threading import Thread
import tkinter as tk
from tkinter import font as tkfont
from tkinter import ttk
class Chat(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
self.title('Chat')
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (Login, MainFrame):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("Login")
container.menubar = tk.Menu(container)
for i in ['File','Edit','About']:
menu = tk.Menu(container.menubar, tearoff=0)
container.menubar.add_cascade(label=i, menu=menu)
self.config(menu=container.menubar)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class Login(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.parent=parent
label = tk.Label(self, text="Please enter your name", font="SegoeUI 40")
self.entry = tk.Entry(self,font = "SegoeUI 20")
button = tk.Button(self, text="Join Chat",command=self.buttonPress,font="SegoeUI 25",background='#00c38a',foreground='#ffffff')
self.error=tk.Label(self,font='SegoeUI 20')
label.grid(row=1,column=1,sticky='WE',padx=20,pady=(10,10))
self.entry.grid(row=2,column=1,sticky='WE',padx=20,pady=10)
button.grid(row=3,column=1,sticky='WE',padx=20,pady=30)
self.error.grid(row=4,column=1)
self.grid_columnconfigure((0,2),weight=1)
self.grid_rowconfigure((0,5),weight=1)
def buttonPress(self):
try:
self.controller.username=self.entry.get()
if self.controller.username:
self.controller.frames['MainFrame'].Main.connectServer()
self.controller.frames['MainFrame'].Main.send(user=self.controller.username)
self.controller.show_frame("MainFrame")
else:
self.error["text"]="Username can't be blank"
except ConnectionRefusedError:
del self.controller.frames['MainFrame'].Main.client_socket
self.error["text"]="Can't connect to server - please try again"
class MainFrame(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background='#393939')
self.chatBar=ItemList(self,[('Year',i+1) for i in range(12,5,-1)],'Chat Rooms')
self.userList=ItemList(self,["maksovnik","bobsmith"],'User List')
self.Main=MainChat(self,controller)
self.chatBar.grid(row=1,column=0,padx=20,pady=20,sticky='NS')
self.userList.grid(row=1,column=2,padx=20,pady=20,sticky='ENS')
self.Main.grid(row=1,column=1,sticky='wens',padx=30,pady=20)
self.grid_columnconfigure(1,weight=1)
self.grid_rowconfigure((0,2),weight=1)
controller.protocol("WM_DELETE_WINDOW", self.Main.on_closing)
class ItemList(tk.Frame):
def __init__(self,parent,items,text):
tk.Frame.__init__(self, parent)
helv36 = tkfont.Font(family="SegoeUI",size=16)
helv37 = tkfont.Font(family="SegoeUI",size=16, weight='bold')
self.title=tk.Label(self,text=text,background='#545454',font=helv37,foreground='#ffffff')
self.listbox = tk.Listbox(self,font=helv36,width=15,height=20,background='#5e5e5e',selectbackground='#d39b46',highlightthickness='0',foreground='#ffffff',activestyle='none')
self.title.pack(fill=tk.BOTH, expand=1)
self.listbox.pack(fill=tk.BOTH, expand=1)
self.setItems(items)
def setItems(self,items):
self.listbox.delete(0, tk.END)
self.contents=[]
for x in items:
self.contents.append(x)
self.listbox.insert(tk.END,x)
class MainChat(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self, parent)
self.messages=[]
self.parent=parent
#self.Chat = tk.Text(self)
self.msg_list = tk.Listbox(self, height=15, width=85)
self.controller=controller
self.my_msg = tk.StringVar()
self.enter = tk.Entry(self,textvariable=self.my_msg)
self.sendb=tk.Button(self,text='Send',command= self.send)
self.msg_list.pack(expand=True, fill=tk.BOTH)
self.enter.pack(expand=True, fill=tk.BOTH,side=tk.LEFT)
self.sendb.pack(side=tk.RIGHT, fill=tk.BOTH)
#.protocol("WM_DELETE_WINDOW", MainChat.on_closing)
def connectServer(self):
HOST = (so.gethostbyname(so.gethostname()))
#HOST= '192.168.1.184'
PORT = 33000 # Default value.
self.BUFSIZ = 1024
ADDR = (HOST, PORT)
self.client_socket = socket(AF_INET, SOCK_STREAM)
self.client_socket.connect(ADDR)
self.receive_thread = Thread(target=self.receive)
self.receive_thread.start()
def receive(self):
while True:
try:
msg = self.client_socket.recv(self.BUFSIZ).decode("utf8")
if ':' in msg or msg[:7] =='Welcome':
self.msg_list.insert(tk.END, msg)
if msg.split(':')[0]==self.controller.username:
self.msg_list.itemconfig("end", bg = "#d3eeff")
else:
msg=msg.split(' ')
users=msg[0].split(',')
msg=' '.join(msg[1:])
self.msg_list.insert(tk.END, msg)
self.parent.userList.listbox.delete(0,tk.END)
for i in users:
self.parent.userList.listbox.insert(tk.END, i)
except:
break
def send(self,event=None,user=None):
if user!=None:
msg=user
else:
msg = self.my_msg.get()
self.my_msg.set("")
self.client_socket.send(bytes(msg, "utf8"))
if msg == "quit":
self.client_socket.close()
self.quit()
del self.client_socket
def on_closing(self,event=None):
if hasattr(self, 'client_socket'):
self.my_msg.set("quit")
self.send()
print('RAN')
self.controller.destroy()
app = Chat()
app.mainloop()
尝试关闭客户端时,服务器正在运行错误:
D:\Chat\Latest>"../../Python35/python.exe" server.py
Waiting for connection...
192.168.1.184:58404 has joined with username asd
Exception in thread Thread-2:
Traceback (most recent call last):
File "D:\Python35\lib\threading.py", line 923, in _bootstrap_inner
self.run()
File "D:\Python35\lib\threading.py", line 871, in run
self._target(*self._args, **self._kwargs)
File "server.py", line 34, in handle_client
client.send(bytes("quit", "utf8"))
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
非常感谢您的帮助,谢谢! 马克