退出时出现ConnectionResetError

时间:2019-05-16 02:00:43

标签: python multithreading sockets tkinter

我正在尝试使用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

非常感谢您的帮助,谢谢! 马克

0 个答案:

没有答案