current position:Home>Python chat room (Tkinter writing interface, streaming, socket to realize private chat, group chat, check chat records, Mysql to store data)

Python chat room (Tkinter writing interface, streaming, socket to realize private chat, group chat, check chat records, Mysql to store data)

2022-01-29 12:30:06 stormzhuo

One 、 summary

Use python Realize the function of chat room , The main functions are Group chat , The private chat Two ways to chat . The way of implementation is to use Socket programming and Multithreading treading.

The interface uses Python Self contained tkinter Module written , It contains Three interfaces , Namely Sign in <, register as well as Chat interface . And the chat interface Nested sub window , Use and display Chat record . For user data mysql Storage

Two 、mysql preparation

First in mysql Create a database , You can directly use the following statement

CREATE DATABASE python_chat

Then executing the following code will automatically create a table ( Be careful : Remember to change the password
chat_create_mysql.py

import pymysql
Connection = pymysql.connect(host="localhost", user="root", password="jin1687062650", db="python_chat")
cursor = Connection.cursor()
sql_create_table = ''' create table user_information ( user_name varchar (20), password varchar (20), data BLOB ) '''
cursor.execute(sql_create_table)
cursor.close()

3、 ... and 、 Database module

The code is as follows
chat_mysql.py

import pymysql
import sys
class LogInformation(object):
    @staticmethod  #  Static functions are easy to call 
    def login_check(user_name, password):  #  Check user login 
        db = pymysql.connect(host="localhost", user="root", password="jin1687062650", db="python_chat")  #  Associated database 
        cursor = db.cursor()  #  Get database cursor 
        sql = "SELECT * FROM user_information where user_name = '%s' " % (user_name)  #  Database language , Press id lookup 
        try:
            cursor.execute(sql)  #  Cursor execution database language 
            results = cursor.fetchone()  #  Accept all eligible objects 
            db.close()  #  Close the database 
            if password == results[1]:  #  If the passwords are equal, return True
                return True
            else:
                return False
        except:
            return False

    @staticmethod  #  Static functions are easy to call 
    def create_new_user(user_name, password, file_name):  #  Create a new user 
        db = pymysql.connect(host="localhost", user="root", password="jin1687062650", db="python_chat")  #  Associated database 
        cursor = db.cursor()  #  Get database cursor 
        fp = open(file_name, 'rb')  #  Open avatar path 
        img = fp.read()  #  Read avatar 
        sql = "INSERT INTO user_information VALUES (%s,%s,%s);"  #  Database language , Insert user data 
        args = (user_name, password, img)
        try:
            cursor.execute(sql, args)   #  Cursor execution database language 
            db.commit()  #  Submit 
            db.close()  #  Close database connection 
            print(" Insert the success ")
            return "0"
        except:
            print(" Database error ")
            db.rollback()  #  Rollback on error 
            db.close()  #  Close database connection 

    @staticmethod  #  Static functions are easy to call 
    def select_user_name(user_name):  #  Check if the user name already exists 
        db = pymysql.connect(host="localhost", user="root", password="jin1687062650", db="python_chat")  #  Associated database 
        cursor = db.cursor()  #  Get database cursor 
        sql = "SELECT * FROM user_information where user_name = '%s' " % (user_name)  #  Database language , Search by user name 
        try:
            cursor.execute(sql)  #  Cursor execution database language 
            results = cursor.fetchone()  #  Accept all eligible objects 
            # 1 Represents an existing user , 0 Representatives can register 
            if results!=None:
                db.close()  #  Close the database 
                return "1"
            else:
                db.close()  #  Close the database 
                return "0"
        except:
            print(" Database error ")
            db.close()  #  Close the database 

    @staticmethod #  Static functions are easy to call 
    def fing_face(user_name):  #  Look for avatars , Used to display avatar in chat interface 
        try:
            conn = pymysql.connect(host='localhost', user='root',
                               password='jin1687062650', db='python_chat')  #  Associated database 
            cursor = conn.cursor()  #  Get database cursor 
            sql = "SELECT * FROM user_information where user_name = '%s' " % (user_name)  #  Database language , Search by user name 
            cursor.execute(sql)   #  Cursor execution database language 
            fout = open(' The avatars .png', 'wb')  #  Open the path where the user's Avatar is stored 
            fout.write(cursor.fetchone()[2])  #  Write avatar data 
            fout.close()  #  Closed flow 
            cursor.close()  #  Close cursor 
            conn.close()   #  Close the database 
        except pymysql.Error as e:
            print("Error %d: %s" % (e.args[0], e.args[1]))
            sys.exit(1)

The code is explained as follows
The user login , Registration will send a request to the server , After the server receives the request , It will call chat_mysql Check whether the user data is the same as the data in the database or insert the user data for registration .

Four 、tkinter Implement three interfaces

tkinter brief introduction : Tkinter( Also called Tk Interface ) yes Tk GUI toolkit standard Of Python Interface .Tk It's a lightweight cross platform gui (GUI) development tool .

The login interface realizes

The code is as follows
chat_login_panel.py

from tkinter import *  #  The import module , The user to create GUI Interface 

#  Login interface class 
class LoginPanel:

    #  Construction method , The parameter is the button event handling function , From the client main Come in , Button callback can be realized 
    def __init__(self, handle_login, handle_register, close_login_window):
        #  Initialization parameter instance variable 
        self.handle_login = handle_login
        self.handle_register = handle_register
        self.close_login_window = close_login_window

    #  Example method of displaying login interface 
    def show_login_panel(self):
        #  Declaring global variables is convenient , Call again in a static function 
        global login_frame
        global frames
        global imgLabel
        global numIdx

        self.login_frame = Tk()  #  Create main window 
        #  Set the background color 
        self.login_frame.configure(background="white")
        login_frame = self.login_frame  #  Bind global variables 

        #  Set the window close button callback , Used to close on exit socket Connect 
        self.login_frame.protocol("WM_DELETE_WINDOW", self.close_login_window)

        #  Get the screen width , Height 
        screen_width = self.login_frame.winfo_screenwidth()
        screen_height = self.login_frame.winfo_screenheight()
        #  Declaration width , Height variable 
        width = 503
        height = 400
        #  Set the window variable in the screen 
        gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
                                  (screen_height - 1.2 * height) / 2)
        self.login_frame.geometry(gm_str)  #  Set window office 
        self.login_frame.title(" Sign in ")   #  Set the window title 
        #  The setting window cannot be resized 
        self.login_frame.resizable(width=False, height=False)

        numIdx = 10  # gif The number of frames 
        #  Loop through the frame of the moving graph 
        frames = [PhotoImage(file='login.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
        #  Create and store gif The label of 
        imgLabel = Label(self.login_frame, height=400, width=500)
        #  Set the location of the label 
        imgLabel.place(x=-252, y=-200, relx=0.5, rely=0.5, relwidth=1, relheigh=0.5)

        #  Set the text label and position 
        Label(login_frame, text=" nickname :", font=(" Song style ", 12), bg="white", fg="grey") \
            .place(x=110, y=230)
        Label(login_frame, text=" password :", font=(" Song style ", 12), bg="white", fg="grey") \
            .place(x=110, y=260)

        #  Declare user name and password variables 
        self.user_name = StringVar()
        self.password = StringVar()

        #  Set the input box and position 
        self.entry1=Entry(login_frame,  textvariable=self.user_name, fg="black", width=25)
        self.entry1.place(x=180, y=230)
        self.entry2=Entry(login_frame, textvariable=self.password, show='*', fg="black", width=25)
        self.entry2.place(x=180, y=260)

        #  Set the registration button and location , The button event is handle_register function 
        self.button_register = Button(login_frame, text=" Registered account ", relief=FLAT, bg='white', fg='grey',
                             font=(' In black ', 15), command=self.handle_register).place(x=0, y=370)

        self.login_frame.bind('<Return>', self.handle_login)  #  Bind the Enter key 
        #  Set login button and location , The button event is handle_login function 
        self.button_login = Button(login_frame, text=" Sign in ", bg="#00BFFF", fg="white", width=21, height=2,
                                font=(' In black ', 15), command=lambda: self.handle_login(self))
        self.button_login.place(x=160, y=300)

    #  Timer Functions , Used to refresh gif Frame of 
    @staticmethod
    def update(idx):
        frame = frames[idx]
        idx += 1  #  The serial number of the next one 
        imgLabel.configure(image=frame)
        login_frame.after(200, LoginPanel.update, idx % numIdx)  # 200 After milliseconds, continue to execute the timer function 

    #  Call the timer function , Execute loop mainloop Display interface instance method 
    def load(self):
        LoginPanel.update(0)
        self.login_frame.mainloop()

    #  Close the login interface instance method 
    def close_login_panel(self):
        if self.login_frame == None:
            print(" The interface is not displayed ")
        else:
            #  Close the login screen 
            self.login_frame.destroy()

    #  Get the input username and password instance method 
    def get_input(self):
        return self.user_name.get(), self.password.get()

Be careful : The above module is called for the client , Running alone has no effect , The startup method will be introduced later . The following shows the effect of the client calling the login module

 Insert picture description here

The code is explained as follows
Create a login interface module chat_login_panel, It contains a login interface class LoginPanel, Construction method of class init Is to initialize the function passed in from the client , Use and to handle button events , When the user clicks the button, it will call back to the client for processing .

Example method show_login_panel Is to encapsulate the components , In this way, users can create multiple login interfaces without interfering with each other , Realize multi person login , Each instance object is different .

Example method close_login_panel,get_input Close the login interface , Get the user name and password entered by the user .

Static functions update It's a timer. , Used to refresh gif Moving graph .

Example method load The function of is to call the timer function updata And execute loop functions login_frame.mainloop Displayed in the login_show_panel Create an interface login_frame

Client call procedure : When the user executes main The module is created LoginPanel object , The create object procedure calls init How to construct mian The functions in the module are initialized as parameters and become instance variables , Event handling as a button . After creating the object, you can call the instance method of the object with the object .

First call <ogin_show_panel The instance method creates components and layouts , And then call load Execute the timer function to refresh the dynamic diagram and mainloop Loop function display interface .

client main The module will give , The registration interface and chat interface are the same as the login interface

Registration interface implementation

The code is as follows

chat_login_panel.py

from tkinter import *  #  The import module , The user to create GUI Interface 
from PIL import Image  #  Import image processing module 

#  Register interface class 
class RegisterPanel(object):

    #  Construction method , The parameter is the button event handling function , From the client main Come in , Button callback can be realized 
    def __init__(self, file_open_face, close_register_window, register_submit):
        #  Initialization parameter instance variable 
        self.file_open_face = file_open_face
        self.close_register_window = close_register_window
        self.register_submit = register_submit
        self.file_name = ""  #  File path 

    #  Display instance method of registration interface 
    def show_register_panel(self):
        #  Declaring global variables is convenient , Call again in a static function 
        global register_frame
        global frames
        global imgLabel
        global numIdx

        #  Create main window 
        self.register_frame = Tk()
        register_frame = self.register_frame  #  Bind global variables 
        #  Set the background color 
        self.register_frame.configure(background="white")
        #  Get the screen width , Height 
        screen_width = self.register_frame.winfo_screenwidth()
        screen_height = self.register_frame.winfo_screenheight()
        #  Declaration width , Height variable 
        width = 503
        height = 400
        #  Set the window variable in the screen 
        gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
                                  (screen_height - 1.2 * height) / 2)
        #  Set window office 
        self.register_frame.geometry(gm_str)
        #  Set the window title 
        self.register_frame.title(" register ")
        #  The setting window cannot be resized 
        self.register_frame.resizable(width=False, height=False)

        self.p1 = PhotoImage(file=' Add avatar button .png')  #  Turn the picture into PhotoImage type 

        numIdx = 9  # gif The number of frames 
        #  Loop through the frame of the moving graph 
        frames = [PhotoImage(file='register.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
        #  Create and store gif The label of 
        imgLabel = Label(self.register_frame, height=400, width=500)
        #  Set the location of the label 
        imgLabel.place(x=-252, y=-200, relx=0.5, rely=0.5, relwidth=1, relheigh=0.5)

        #  Set text box , Users store avatars 
        self.face_show = Text(self.register_frame, bg="white", height=3.5, width=7,
                                 highlightcolor="white")
        #  Set the text box to be non editable 
        self.face_show.config(state=DISABLED)
        #  Set the position of the text box 
        self.face_show.place(x=370, y=230)

        #  Declare width and height , Used to set the picture size 
        self.width = 50
        self.height = 50
        #  Open the picture , Used to display the default avatar in the text box of the registration page 
        img = Image.open(" Default Avatar .png")
        #  Set the size of the picture 
        out = img.resize((self.width, self.height), Image.ANTIALIAS)
        #  Save the picture , The type is png
        out.save(r" Head portrait .png", 'png')

        #  Convert the avatar to PhotoImage type , Used to display... In a text box 
        self.p2 = PhotoImage(file=' Head portrait .png')
        #  Set the text box to be editable 
        self.face_show.config(state=NORMAL)
        #  Insert the avatar picture into the text box 
        self.face_show.image_create(END, image=self.p2)
        #  Set the text box to be non editable 
        self.face_show.config(state=DISABLED)
        #  Set the text box to slide to the lowest position 
        self.face_show.see(END)

        #  Set text label and position 
        Label(self.register_frame, text=" user name :", font=(" Song style ", 12), bg="white", fg="grey") \
            .place(x=60, y=230)
        Label(self.register_frame, text=" The secret   code :", font=(" Song style ", 12), bg="white", fg="grey") \
            .place(x=60, y=260)
        Label(self.register_frame, text=" Confirm the password :", font=(" Song style ", 12), bg="white", fg="grey") \
            .place(x=60, y=290)

        #  Declare user name , password , Confirm password variable 
        self.user_name = StringVar()
        self.password = StringVar()
        self.confirm_password = StringVar()

        #  Set the input text box and position , Used to get user input 
        Entry(self.register_frame, textvariable=self.user_name, fg="black", width=30) \
            .place(x=140, y=230)
        Entry(self.register_frame, textvariable=self.password, show="*", fg="black", width=30) \
            .place(x=140, y=260)
        Entry(self.register_frame, textvariable=self.confirm_password, show="*", fg="black", width=30) \
            .place(x=140, y=290)

        #  Set the exit registration page button and location , The button event is close_register_window function 
        self.botton_quit = Button(self.register_frame, text=" return ",  relief=FLAT, bg='white', fg="grey",
                               font=(' In black ', 15), command=self.close_register_window).place(x=0, y=370)

        self.register_frame.bind('<Return>', self.register_submit)  #  Bind registration button enter event 
        #  Set the registration button and location , The button event is register.submit function 
        self.botton_register = Button(self.register_frame, text=" Register now ", bg="#00BFFF", fg="white", width=27, height=2,
                              font=(' In black ', 15), command=lambda: self.register_submit(self)).place(x=120, y=330)

        #  Set the add avatar button and position , Event handling is file_open_face function 
        self.botton_file_open = Button(self.register_frame, image=self.p1, relief=FLAT, bd=0,
                                       command=self.file_open_face).place(x=430, y=230)

    #  Timer static function , Used to refresh gif Frame of 
    @staticmethod
    def update(idx):
        frame = frames[idx]
        idx += 1  #  The serial number of the next one 
        imgLabel.configure(image=frame)
        register_frame.after(200, RegisterPanel.update, idx % numIdx)  # 200 After milliseconds, continue to execute the timer function 

    #  Call the timer function , Execute loop mainloop Display interface instance method 
    def load(self):
        RegisterPanel.update(0)
        self.register_frame.mainloop()

    #  Add avatar instance method 
    def add_face(self, file_name):
        self.file_name = file_name
        #  Open the picture 
        img = Image.open(file_name)
        #  Set picture size 
        out = img.resize((self.width, self.height), Image.ANTIALIAS)
        #  Save the picture , The type is png
        out.save(r" Head portrait .png", 'png')
        #  Turn the avatar into PhotoImage
        self.p = PhotoImage(file=' Head portrait .png')
        #  Set the text box to be editable 
        self.face_show.config(state=NORMAL)
        self.face_show.delete('0.0', END)
        #  Insert the avatar into the text box 
        self.face_show.image_create(END, image=self.p)
        #  Set text not editable 
        self.face_show.config(state=DISABLED)
        #  Set the text box to slide to the lowest position 
        self.face_show.see(END)

    #  Close the instance method of the registration interface 
    def close_register_panel(self):
        if self.register_frame == None:
            print(" The interface is not displayed ")
        else:
            #  Close the registration interface 
            self.register_frame.destroy()

    #  Get the entered user name 、 password 、 Confirm password instance method 
    def get_input(self):
        return self.user_name.get(), self.password.get(), self.confirm_password.get(), self.file_name

design sketch

 Insert picture description here

Chat interface implementation

The code is as follows

chat_main_panel.py

from tkinter import *  #  The import module , The user to create GUI Interface 
import tkinter.font as tf  #  Class that handles font styles and colors 
import time
import chat_mysql  #  Import processing mysql Module 
from PIL import Image  #  Import image processing module 

#  Main interface class 
class MainPanel:
    #  Construction method , The parameter is the button event handling function , From the client main Come in , Button callback can be realized 
    def __init__(self, user_name, send_message, send_mark, refurbish_user, private_talk, close_main_window):
        #  Initialization parameter instance variable 
        self.user_name = user_name
        self.send_message = send_message
        self.send_mark = send_mark
        self.refurbish_user = refurbish_user
        self.private_talk = private_talk
        self.close_main_window = close_main_window
        #  Use the dictionary to match the mark with the expression picture one by one ,  Used to receive marks later to judge the expression map 
        self.dic = {
    }
        self.ee = 0  #  Mark for judging the switch of expression panel 
        self.face = []  #  Store avatar list 

    def show_main_panel(self):
        #  Declare global variables , Easy to invoke in static function 
        global main_frame
        global frames
        global imgLabel
        global numIdx

        #  Create main window 
        main_frame = Tk()
        #  Bind global variables to instance variables 
        self.main_frame = main_frame
        #  Set main window title 
        self.main_frame.title("python The chat room ")
        #  Set the main window color 
        self.main_frame.configure(background="white")
        #  Set the callback function to close the main window 
        self.main_frame.protocol("WM_DELETE_WINDOW", self.close_main_window)
        #  Declaration width , The height variable is used to set the height in the main window 
        width = 1300
        height = 700
        #  Get the height of the screen , Width 
        screen_width = self.main_frame.winfo_screenwidth()
        screen_height = self.main_frame.winfo_screenheight()
        #  Set the variables in the main window 
        gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
                                  (screen_height - 1.2 * height) / 2)
        #  Set the office in the main window 
        self.main_frame.geometry(gm_str)
        #  The setting window cannot be resized 
        self.main_frame.resizable(width=False, height=False)

        #  Expression picture , Convert the picture to PhotoImage,
        self.p1 = PhotoImage(file=' WeChat expression 1.png')
        self.p2 = PhotoImage(file=' WeChat expression 2.png')
        self.p3 = PhotoImage(file=' WeChat expression 3.png')
        self.p4 = PhotoImage(file=' WeChat expression 4.png')
        self.p5 = PhotoImage(file=' WeChat expression 5.png')
        self.p6 = PhotoImage(file=' WeChat expression 6.png')
        self.p7 = PhotoImage(file=' WeChat expression 7.png')
        self.p8 = PhotoImage(file=' WeChat expression 8.png')
        self.p9 = PhotoImage(file=' WeChat expression 9.png')
        self.p10 = PhotoImage(file=' WeChat expression 10.png')

        #  Button image , Convert the picture to PhotoImage
        self.p11 = PhotoImage(file=' Emoticon button .png')
        self.p12 = PhotoImage(file=' Chat button .png')

        #  Expression pack Dictionary , Each expression package corresponds to a mark 
        self.dic = {
    'aa**': self.p1, 'bb**': self.p2, 'cc**': self.p3, 'dd**': self.p4, 'ee**': self.p5,
                    'ff**': self.p6, 'gg**': self.p7, 'hh**': self.p8, 'jj**': self.p9, 'kk**': self.p10}

        #  Set the text label and position 
        self.label1 = Label(self.main_frame, text="  Online users  python Welcome to chat room :" + self.user_name + " "
                                                                                                      " "
                                                                                                      " " +
                                                  " ", font=(" In black ", 20), bg="#00BFFF", fg="white")
        self.label1.grid(row=0, column=0, ipady=0, padx=0, columnspan=3, sticky=E+W)

        #  Online user list box 
        friend_list_var = StringVar()  #  Declare list box variables 
        #  Set the list box and location 
        self.friend_list = Listbox(self.main_frame, selectmode=NO, listvariable=friend_list_var,
                                   bg="#F8F8FF", fg="#00BFFF", font=(" Song style ", 14),
                                   highlightcolor="white", selectbackground="#00BFFF")
        self.friend_list.grid(row=1, column=0, rowspan=3, sticky=N + S, padx=0, pady=(0, 0))
        self.friend_list.bind('<ButtonRelease-1>', self.private_talk)  #  Bind list box click event 
        #  Set the scale of the list box 
        main_frame.rowconfigure(1, weight=1)  #  Set the scaling of the first row of the main window , That is, the list box 
        main_frame.columnconfigure(1, weight=1)  #  Set the scale of the column 

        sc_bar = Scrollbar(self.main_frame, activebackground='red')  #  Set the list box scroll bar 
        sc_bar.grid(row=1, column=0, sticky=N + S + E, rowspan=3, pady=(0, 3))  #  Set the position of the scroll bar 

        #  Binding of list box and scroll bar 
        sc_bar['command'] = self.friend_list.yview
        self.friend_list['yscrollcommand'] = sc_bar.set

        #  Set the scroll bar of the message box 
        msg_sc_bar = Scrollbar(self.main_frame)  #  Set scroll bar 
        msg_sc_bar.grid(row=1, column=1, sticky=E + N + S, padx=(0, 1), pady=1)  #  Set the position of the scroll bar 

        #  The text box that displays the message 
        self.message_text = Text(self.main_frame, bg="white", height=1,
                            highlightcolor="white", highlightthickness=1)
        #  The text box that displays the message is not editable , When the content needs to be modified, the version can be modified to the editable mode  NORMAL
        self.message_text.config(state=DISABLED)
        #  Set the location of the message box 
        self.message_text.grid(row=1, column=1, sticky=W + E + N + S, padx=(0, 15), pady=(0, 27))

        numIdx = 6  # gif The number of frames 
        #  Loop through the frame of the moving graph 
        frames = [PhotoImage(file='main.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
        #  Create storage gif The label of 
        imgLabel = Label(self.main_frame, height=400, width=490)
        #  Set the location of the label 
        imgLabel.grid(row=1, column=2, sticky=W + E + N + S, rowspan=100, padx=(0, 0), pady=(160, 175))

        #  Bind message box and message box scroll bar 
        msg_sc_bar["command"] = self.message_text.yview
        self.message_text["yscrollcommand"] = msg_sc_bar.set

        #  Set the send message box scroll bar 
        send_sc_bar = Scrollbar(self.main_frame)  #  Create a scroll bar 
        #  Set the position of the scroll bar 
        send_sc_bar.grid(row=2, column=1, sticky=E + N + S, padx=(0, 1), pady=1)

        #  Send message box 
        self.send_text = Text(self.main_frame, bg="white", height=11, highlightcolor="white",
                         highlightbackground="#444444", highlightthickness=0)
        #  Scroll to the bottom 
        self.send_text.see(END)
        #  Set the location of the message box 
        self.send_text.grid(row=2, column=1, sticky=W + E + N + S, padx=(0, 15), pady=0)

        #  Bind send message box and send message box scroll bar 
        send_sc_bar["command"] = self.send_text.yview
        self.send_text["yscrollcommand"] = send_sc_bar.set

        self.main_frame.bind('<Return>', self.send_message)  #  Bind send button enter event 

        #  Set the send message button and location , The event handler is send_message
        button1 = Button(self.main_frame, command=lambda: self.send_message(self), text=" send out ", bg="#00BFFF",
                         fg="white", width=13, height=2, font=(' In black ', 12),)
        button1.place(x=650, y=640)

        #  Set the close window button and position , The event handler is close_main_window
        button2 = Button(self.main_frame, text=" close ", bg="white", fg="black", width=13, height=2,
                              font=(' In black ', 12), command=self.close_main_window)
        button2.place(x=530, y=640)

        #  Set the expression pack button and position , Event handling is an instance method express
        botton4 = Button(self.main_frame, command=self.express, image=self.p11, relief=FLAT, bd=0)
        botton4.place(x=214, y=525)

        #  Set the chat record button and location , Event handling is create_window Example method 
        botton5 = Button(self.main_frame, command=self.create_window, image=self.p12, relief=FLAT, bd=0)
        botton5.place(x=250, y=525)

        #  Set the refresh user list button and location , Event handling is refurbish_user function 
        botton5 = Button(self.main_frame, command=self.refurbish_user, text=" Refresh online users ", bg="#00BFFF", fg="white",
                         width=13, height=2, font=(' In black ', 12),)
        botton5.place(x=40, y=650)

    #  Definer static function , Used to refresh gif Frame of 
    @staticmethod
    def update(idx):
        frame = frames[idx]
        idx += 1  #  The serial number of the next one 
        imgLabel.configure(image=frame)
        main_frame.after(100, MainPanel.update, idx % numIdx)  # 100 After milliseconds, continue to execute the timer function 

    #  Call the timer function , Execute loop mainloop Display interface instance method 
    def load(self):
        MainPanel.update(0)
        self.main_frame.mainloop()

    #  Chat record button event handling instance method 
    def create_window(self):
        top1 = Toplevel()  #  Create subwindow 
        top1.configure(background="#FFFAFA")  #  Set sub window color 
        #  Get the screen width , Height 
        screen_width = top1.winfo_screenwidth()
        screen_height = top1.winfo_screenheight()
        #  Declaration width , Height variable 
        width = 600
        height = 650
        #  Set the window variable in the screen 
        gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
                                  (screen_height - 1.2 * height) / 2)
        top1.geometry(gm_str)  #  Set window office 
        top1.title(" Chat record ")  #  Set the window title 
        #  The setting window cannot be resized 
        top1.resizable(width=False, height=False)

        #  Set text labels 
        title_lable = Label(top1, text=" Chat record ", font=(' Rough italics ', 20, 'bold italic'),
                            fg="white", bg="#00BFFF")
        #  Set the position of the text in the window 
        title_lable.pack(ipady=10, fill=X)

        #  Set text box , Users store chat record information 
        self.chatting_records = Text(top1, bg="white", height=50, highlightcolor="white", highlightthickness=1)
        #  Set location 
        self.chatting_records.pack(ipady=10, fill=X)
        #  The text box that displays the message is not editable , When the content needs to be modified, the version can be modified to the editable mode  NORMAL
        self.chatting_records.config(state=DISABLED)

        #  Set the button and position for clearing chat records , The event handler is clear_chatting_records Example method 
        botton = Button(top1,  text=" Clear chat ", command=self.clear_chatting_records, bg="#00BFFF",
                        fg="white", width=12, height=2, font=(' In black ', 11))
        botton.place(x=490, y=600)

        #  Call the instance method to display the chat record 
        self.show_chatting_records()

    #  Example method of displaying chat records 
    def show_chatting_records(self):
        #  Set the text box to be editable 
        self.chatting_records.config(state=NORMAL)
        #  Open the user's local file for storing chat records 
        f = open("C:/Program Files (x86)/pythonProject/chatting_records/" + self.user_name + ".txt", 'r')
        while True:
            content = f.readline()  #  Read one line at a time 
            ft = tf.Font(family=' Microsoft YaHei ', size=13)  #  Set font style and size variables 
            #  Set color and font style and size 
            self.chatting_records.tag_config("tag_9", foreground="#00BFFF", font=ft)
            if content != "":  #  If it is not empty, insert text in the last line of the text box 
                self.chatting_records.insert(END, content, 'tag_9')
            else:
                self.chatting_records.config(state=DISABLED)  # Otherwise, set the text box to be non editable 
                return

    #  Clear chat record button processing instance method 
    def clear_chatting_records(self):
        #  Set the text box to be editable 
        self.chatting_records.config(state=NORMAL)
        self.chatting_records.delete('1.0', END)   #  Delete the contents of the text box 
        #  Open the chat log file , Write content as an overlay 
        a = open("C:C:/Program Files (x86)/pythonProject/chatting_records/" + self.user_name + ".txt",
                 'w')
        a.write("")  #  Insert empty string , The chat record will be overwritten 
        a.close()  #  close 
        self.chatting_records.config(state=DISABLED)  #  Set text not editable 

    #  How to save chat record instances 
    def sava_chatting_records(self, content):
        #  Open the chat log file 
        a = open("C:/Program Files (x86)/pythonProject/chatting_records/" + self.user_name + ".txt", 'a')
        a.write(content)   #  Write information 
        a.close()  #  close 

    #  Define the method of handling event instance of expression package button 
    def express(self):
        #  If ee Marked as 0, Then pop up the expression package , Or destroy the expression pack 
        if self.ee == 0:
            self.ee = 1   #  Set the tag to 1, Used to destroy the expression the next time you click the button 
            #  Set emoticon button and corresponding event handling instance method 
            self.b1 = Button(self.main_frame, command=self.bb1, image=self.p1, relief=FLAT, bd=0)
            self.b2 = Button(self.main_frame, command=self.bb2, image=self.p2, relief=FLAT, bd=0)
            self.b3 = Button(self.main_frame, command=self.bb3, image=self.p3, relief=FLAT, bd=0)
            self.b4 = Button(self.main_frame, command=self.bb4, image=self.p4, relief=FLAT, bd=0)
            self.b5 = Button(self.main_frame, command=self.bb5, image=self.p5, relief=FLAT, bd=0)
            self.b6 = Button(self.main_frame, command=self.bb6, image=self.p6, relief=FLAT, bd=0)
            self.b7 = Button(self.main_frame, command=self.bb7, image=self.p7, relief=FLAT, bd=0)
            self.b8 = Button(self.main_frame, command=self.bb8, image=self.p8, relief=FLAT, bd=0)
            self.b9 = Button(self.main_frame, command=self.bb9, image=self.p9, relief=FLAT, bd=0)
            self.b10 = Button(self.main_frame, command=self.bb10, image=self.p10, relief=FLAT, bd=0)
            #  Set the location of the emoticon pack 
            self.b1.place(x=207, y=480)
            self.b2.place(x=255, y=480)
            self.b3.place(x=303, y=480)
            self.b4.place(x=351, y=480)
            self.b5.place(x=399, y=480)
            self.b6.place(x=207, y=430)
            self.b7.place(x=255, y=430)
            self.b8.place(x=303, y=430)
            self.b9.place(x=351, y=430)
            self.b10.place(x=399, y=430)
        else:
            #  Mark ee by 0 Then destroy all emoticon buttons 
            self.ee = 0
            self.b1.destroy()
            self.b2.destroy()
            self.b3.destroy()
            self.b4.destroy()
            self.b5.destroy()
            self.b6.destroy()
            self.b7.destroy()
            self.b8.destroy()
            self.b9.destroy()
            self.b10.destroy()

    #  All expression button processing instance methods 
    def bb1(self):
        self.mark('aa**')  #  Invoking an instance method , Pass the parameters 

    def bb2(self):
        self.mark('bb**')

    def bb3(self):
        self.mark('cc**')

    def bb4(self):
        self.mark('dd**')

    def bb5(self):
        self.mark('ee**')

    def bb6(self):
        self.mark('ff**')

    def bb7(self):
        self.mark('gg**')

    def bb8(self):
        self.mark('hh**')

    def bb9(self):
        self.mark('jj**')

    def bb10(self):
        self.mark('kk**')

    #  Example method for processing sending expression 
    def mark(self, exp):  #  The parameter is the expression icon of the hair ,  Destroy the button after sending 
        self.send_mark(exp)  #  Function callbacks take tags as arguments 
        #  Destroy all expression packets after sending 
        self.b1.destroy()
        self.b2.destroy()
        self.b3.destroy()
        self.b4.destroy()
        self.b5.destroy()
        self.b6.destroy()
        self.b7.destroy()
        self.b8.destroy()
        self.b9.destroy()
        self.b10.destroy()
        self.ee = 0  #  Set the tag to 0

    #  Refresh online list instance method 
    def refresh_friends(self, online_number, names):
        self.friend_list.delete(0, END)   #  Delete the online list first 
        for name in names:  #  Loop into online users 
            self.friend_list.insert(0, name)
        self.friend_list.insert(0, "【 Group chat 】")  #  Insert group chat in the second line 
        self.friend_list.itemconfig(0, fg="#00BFFF")  #  Set group chat font color 
        self.friend_list.insert(0, ' Number of online users : ' + str(online_number))  #  Insert the number of online users in the first line 
        self.friend_list.itemconfig(0, fg="#FF00FF")  #  Set the number of online users 

    #  The instance method of displaying the message in the interface 
    #  Received the news , Show... In the text box , Your message is in blue , Other people's news is in green 
    def show_send_message(self, user_name, content, chat_flag):
        self.message_text.config(state=NORMAL)   #  Set the message box to be editable 
        #  Set the user name and time variable of the sent message 
        title = user_name + " " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + "\n"
        if content == '*  System prompt : ' + user_name + '  Join the chat room ':  #  Join the chat room for tag processing 
            ft = tf.Font(family=' Microsoft YaHei ', size=13)  #  Set font style and size variables 
            #  Set font color, style and size 
            self.message_text.tag_config("tag_1", foreground="#FF00FF", font=ft)
            self.message_text.insert(END, content + "\n", 'tag_1')  #  Insert the message on the last line 
            self.message_text.config(state=DISABLED)  #  Settings are not editable 
        elif content == '*  System prompt : ' + user_name + '  Has left the group chat ':  #  Leave the chat room to mark processing 
            ft = tf.Font(family=' Microsoft YaHei ', size=13)
            self.message_text.tag_config("tag_2", foreground="#DC143C", font=ft)
            self.message_text.insert(END, content + "\n", 'tag_2')
            self.message_text.config(state=DISABLED)
        elif user_name == self.user_name:  #  If the user sending the message is himself 
            if chat_flag == "group_chat":  #  If the tag is a group chat tag , Your message is in blue 
                ft = tf.Font(family=' Microsoft YaHei ', size=13)
                self.message_text.tag_config("tag_4", foreground="#00BFFF", font=ft)
                self.message_text.insert(END, title, 'tag_4')
                self.sava_chatting_records(title)   #  Call the instance method to save the chat record 
            elif chat_flag == "private_chat":  #  If it's a sign, it's a private chat , The message is in red 
                ft = tf.Font(family=' Microsoft YaHei ', size=13)
                self.message_text.tag_config("tag_5", foreground="#DC143C", font=ft)
                self.message_text.insert(END, title, 'tag_5')
                self.sava_chatting_records(title)
        else:  #  If the user sending the message is not himself 
            if chat_flag == "group_chat":  #  If the tag is group chat , The message is in green 
                ft = tf.Font(family=' Microsoft YaHei ', size=13)
                self.message_text.tag_config("tag_6", foreground="#008000", font=ft)
                self.message_text.insert(END, title, 'tag_6')
                self.sava_chatting_records(title)
            elif chat_flag == "private_chat":  #  It's a private conversation , The message is in red 
                ft = tf.Font(family=' Microsoft YaHei ', size=13)
                self.message_text.tag_config("tag_7", foreground="#DC143C", font=ft)
                self.message_text.insert(END, title, 'tag_7')
                self.sava_chatting_records(title)
        if content in self.dic:  #  Determine whether the message is an expression mark 
            chat_mysql.LogInformation.fing_face(user_name)  #  Go to the database to read the user's Avatar 
            time.sleep(0.5)   #  Set the time buffer , Read the user's Avatar to the database and save the time buffer to the local file 
            #  Open the picture 
            self.img1 = Image.open(" The avatars .png")  #  Open the local file saved in the database 
            #  Set picture size 
            self.out1 = self.img1.resize((50, 50), Image.ANTIALIAS)
            #  Save the picture , The type is png
            self.out1.save(r" The avatars 1.png", 'png')
            time.sleep(0.5)  #  Leave time to cache the modified image size and save the modified image 
            #  Turn the avatar into PhotoImage
            self.face.append(PhotoImage(file=' The avatars 1.png'))  #  Add avatar pictures to the list 
            self.message_text.image_create(END, image=self.face[-1])  #  Insert the last avatar in the list 
            self.message_text.insert(END, " : ")
            self.message_text.image_create(END, image=self.dic[content])   #  Insert an expression 
            self.message_text.insert(END, "\n")
            self.message_text.config(state=DISABLED)
            #  Scroll to the bottom 
            self.message_text.see(END)
        #  The content is the processing of messages 
        elif content != '*  System prompt : ' + user_name + '  Join the chat room ' and content != '*  System prompt : ' + user_name + '  Has left the group chat ':
            chat_mysql.LogInformation.fing_face(user_name)
            time.sleep(0.5)
            #  Open the picture 
            self.img2 = Image.open(" The avatars .png")
            #  Set picture size 
            self.out2 = self.img2.resize((50, 50), Image.ANTIALIAS)
            #  Save the picture , The type is png
            self.out2.save(r" The avatars 2.png", 'png')
            time.sleep(0.5)
            self.face.append(PhotoImage(file=' The avatars 2.png'))
            self.message_text.image_create(END, image=self.face[-1])
            self.message_text.insert(END, " : ")
            ft = tf.Font(family=' Microsoft YaHei ', size=15)
            self.message_text.tag_config("tag_8", foreground="#000000", font=ft)
            self.message_text.insert(END, content, 'tag_8')  #  Insert message 
            self.message_text.config(state=DISABLED)
            #  Scroll to the bottom 
            self.message_text.see(END)
            #  Save the chat 
            self.sava_chatting_records(content)
            self.sava_chatting_records("------------------------------------------------------------------------------\n")

    #  Group chat and private chat are examples of ways to change labels 
    def change_title(self, title):
        self.label1['text'] = title

    #  Clear the instance method of sending message input box 
    def clear_send_text(self):
        self.send_text.delete('0.0', END)

    #  Get the instance method of the content of the message input box 
    def get_send_text(self):
        return self.send_text.get('0.0', END)

design sketch
 Insert picture description here

So far, all interfaces have been realized , These interfaces are encapsulated into classes , Divided into separate modules , Running alone is not effective , Need to pass through main Module is called by the client , Then call the corresponding object instance method through the user's operation

5、 ... and 、 Server implementation

Let's talk about the startup process of the module first , Three interface modules are given above , None of this needs to run , There are only two modules running , They are server and client , The server must first run , And then run the client .

The execution process of the server : When running the server module , Will create a socket, Then bind This machine ip Address And port Connect the request of the listening client , Every time you accept one socket Request , Start a new thread to accept the processing of request messages
The code is as follows
chat_server.py

import socket  #  Import socket socket modular 
from threading import Thread  #  Import multithreaded module 
import math
import chat_mysql  #  Import custom modules for use in mysql Process user data in 

#  Maintain a connection list of online users , For mass messaging 
online_connection = list()
#  Storage socket Correspondence between connection and user 
connection_user = dict()
join_user = ""   #  Users who join the chat room of the storage system 
flag = 0  #  Send the system prompt mark for users to join the chat room 
chat_user = ""  #  Store chat object Tags 

#  A function that sends a string with a length 
def send_string_with_length(_conn, content):
    #  The length of the content sent first 
    _conn.sendall(bytes(content, encoding='utf-8').__len__().to_bytes(4, byteorder='big'))
    #  Then send the content 
    _conn.sendall(bytes(content, encoding='utf-8'))

#  Send a function of the number of online users 
def send_number(_conn, number):
    _conn.sendall(int(number).to_bytes(4, byteorder='big'))

#  Function to get variable length string 
def recv_all_string(connection):
    #  Get message length 
    length = int.from_bytes(connection.recv(4), byteorder='big')
    b_size = 3 * 1024  #  Be careful utf8 Chinese characters account for 3 byte , English 1 byte 
    times = math.ceil(length / b_size)
    content = ''
    for i in range(times):
        if i == times - 1:
            seg_b = connection.recv(length % b_size)
        else:
            seg_b = connection.recv(b_size)
        content += str(seg_b, encoding='utf-8')
    return content

#  Check whether the user name and password are correct 
def check_user(user_name, password):
    #  Call the database module to check the user name and password 
    return chat_mysql.LogInformation.login_check(user_name, password)

#  Add user function 
def add_user(user_name, password, file_name):
    #  Call the functions in the database module to add users , Successfully returns 1, An existing user returned 0, Other errors return 2
    if chat_mysql.LogInformation.select_user_name(user_name) == "1":
        return "1"
    elif chat_mysql.LogInformation.create_new_user(user_name, password, file_name) == "0":
        return "0"
    else:
        return "2"

#  The function that handles the request to refresh the list 
def handle_online_list():
    for con in online_connection:  #  Send messages to all online users 
        send_string_with_length(con, "#!onlinelist#!")  #  Send refresh user list flag 
        #  Send the list first 
        send_number(con, online_connection.__len__())
        for c in online_connection:  #  Send user name 
            send_string_with_length(con, connection_user[c])
    return True

#  Function for processing login request 
def handle_login(connection, address):
    #  Declare global variables , Convenient, can be used in other functions 
    global join_user  #  The declaration stores the users who join the chat room 
    global flag  #  Declare the mark that the user joins the chat room 
    #  Call the function to accept the user name and password sent by the client 
    user_name = recv_all_string(connection)
    password = recv_all_string(connection)
    #  Call the function to check the user name and password 
    check_result = check_user(user_name, password)
    #  If the inspection result is True, Send login flag to client 
    if check_result:
        connection.sendall(bytes("1", "utf-8"))  #  Send login pass flag to client 
        connection_user[connection] = user_name  #  Add the user and connection number to the dictionary , Connect as key , Name as value 
        join_user = user_name   #  Users who join the chat room of the storage system 
        flag = 1  #  Set the flag to true , Send the message of user joining the chat to all clients with 
        online_connection.append(connection)  #  Add the currently connected user to the connection list of online users , For mass messaging 
        handle_online_list()  #  Call the function to refresh the list of online users 
        handle_message(connection, address)   #  Call the function to send the information of users joining the chat room 
    else:
        connection.sendall(bytes("0", "utf-8"))  #  Send login failure flag to the client 
    return True

#  Function for processing registration request 
def handle_register(connection, address):
    #  Call the function to obtain the user name and password in turn 
    user_name = recv_all_string(connection)
    password = recv_all_string(connection)
    file_name = recv_all_string(connection)
    #  Call add user function add_user Returns the value as a token sent to the client ,0 success ,1 There are already users ,2 Other mistakes 
    connection.sendall(bytes(add_user(user_name, password, file_name), "utf-8"))
    return True

#  Processing message sending request function 
def handle_message(connection, address):
    global flag  #  Send a sign that the user joined the chat room 
    global chat_user  #  Chat with 
    if flag == 1:   #  If it is equal to 1 Send join chat message to all clients 
        for c in online_connection:
            send_string_with_length(c, "#!message#!")  #  Send message mark 
            send_string_with_length(c, "group_chat")   #  Send chat object tag , The object is group chat 
            send_string_with_length(c, connection_user[connection])  #  Send the user name to join the chat room 
            content = '*  System prompt : ' + connection_user[connection] + '  Join the chat room '
            send_string_with_length(c, content)  #  Send a message to join the chat room 
    else:  #  Otherwise, call the function to get the chat object , Content 
        chat_user = recv_all_string(connection)
        content = recv_all_string(connection)
        if content == "exit":  #  If the content is exit Mark , Then some users quit the chat room 
            for c in online_connection:  #  Send user exit message to all online users 
                send_string_with_length(c, "#!message#!")  #  Send message mark 
                send_string_with_length(c, "group_chat")   #  Send chat object tag , The object is group chat 
                send_string_with_length(c, connection_user[connection])  #  Send user name to leave the chat room 
                send_string_with_length(c, '*  System prompt : ' + connection_user[connection] + '  Has left the group chat ')   #  Send a message leaving the chat room 
        else:  #  Otherwise, check the chat object 
             if chat_user == "【 Group chat 】":  #  If the chat object is a group chat in the room 
                #  Send to all online clients 
                for c in online_connection:
                    #  First send a string to tell the client, and then the message 
                    send_string_with_length(c, "#!message#!")  #  Send message mark 
                    send_string_with_length(c, "group_chat")  #  Send chat object tag , The object is group chat 
                    send_string_with_length(c, connection_user[connection])   #  The user name of the client who sent the message 
                    send_string_with_length(c, content)  #  Send a message 
             else:  #  Otherwise, the chat object is one-on-one private chat 
                 for c in online_connection:  #  Find someone to chat with 
                     if connection_user[c] == chat_user:  #  Look up objects from the dictionary , If found, execute the following statement 
                         send_string_with_length(c, "#!message#!")  #  Send message mark 
                         send_string_with_length(c, "private_chat")  #  Send chat object tag , For private chat 
                         send_string_with_length(c, connection_user[connection])  #  The user name of the client who sent the message 
                         send_string_with_length(c, content)  #  Send a message 
                         #  Send yourself a message 
                         send_string_with_length(connection, "#!message#!")
                         send_string_with_length(connection, "private_chat")
                         send_string_with_length(connection, connection_user[connection])
                         send_string_with_length(connection, content)
    flag = 0  #  Change the chat mark to 0
    return True

#  The execution function of the processing request thread 
def handle(connection, address):
    try:
        while True:
            #  Accept the type of request sent by the client 
            request_type = str(connection.recv(1024).decode())
            #  Continue processing tags 
            no_go = True
            if request_type == "1":  #  Login request 
                print(" Start processing login request ")
                #  Call the function to process the request 
                no_go = handle_login(connection, address)
            elif request_type == "2":  #  Registration request 
                print(" Start processing registration request ")
                no_go = handle_register(connection, address)
            elif request_type == "3":  #  Send message request 
                print(" Start processing send message request ")
                no_go = handle_message(connection, address)
            elif request_type == "4":  #  Refresh user list request 
                print(" Start processing refresh list request ")
                no_go = handle_online_list()
            if not no_go:
                break
    except Exception as e:
        print(str(address) + "  Abnormal connection , Ready to disconnect : " + str(e))
    finally:
        try:
            connection.close()
            online_connection.remove(connection)
            connection.pop(connection)
        except:
            print(str(address) + " Connection closing exception ")

#  entrance 
if __name__ == "__main__":
    try:
        #  Create a that accepts client connections socket
        server = socket.socket()
        server.bind(('127.0.0.1', 5000))  #  Bind host and port number 
        #  Maximum number of hangs 
        server.listen(10)
        print(" Server started successfully , Start listening ...")
        while True:
            #  Accept the connection of the client and create a sub thread to process the corresponding content 
            connection, address = server.accept()
            Thread(target=handle, args=(connection, address)).start()
    except Exception as e:
        print(" Server error : " + str(e))

6、 ... and 、 Client implementation

chat_client modular

To realize multi person chat , First of all, put socket Encapsulate the class as a module to call the client , In this way, the information of different users can be encapsulated without interference with each other
The code is as follows
chat_client

import math
import socket

class ChatSocket:
    #  Construction method 
    def __init__(self):
        print(" initialization tcp client ")
        #  While creating objects , A connection to the server will be created socket
        self.client_socket = socket.socket()  #  establish socket
        self.client_socket.connect(('127.0.0.1', 5000))  #  Request to connect to the server 

    #  Request login type 
    def login_type(self, user_name, password):
        #  Send request login flag to the server 
        self.client_socket.sendall(bytes("1", "utf-8"))
        #  Call the instance method in turn to send the user name and password to the server 
        self.send_string_with_length(user_name)
        self.send_string_with_length(password)
        #  Call the instance method to get the return value of the server ,"1" On behalf of the through ,“0” Means not to pass 
        check_result = self.recv_string_by_length(1)  #  Call the instance method of this object to get the message of the server 
        return check_result  # True The login request passed on behalf of ,False Delegate login request failed 

    #  Request registration type 
    def register_user(self, user_name, password, file_name):
        #  Send the request registration flag to the server 
        self.client_socket.sendall(bytes("2", "utf-8"))
        #  Call the instance method to send the user name and password avatar path to the server in turn 
        self.send_string_with_length(user_name)
        self.send_string_with_length(password)
        self.send_string_with_length(file_name)
        #  Call the instance method to get the return value 
        # "0" On behalf of the through ,“1” Represents an existing user name , "2" Represents other errors 
        return self.recv_string_by_length(1)

    #  Send message type 
    def send_message(self, message, chat_user):
        #  Send message mark 
        self.client_socket.sendall(bytes("3", "utf-8"))
        #  Call instance method to send chat object , The default is group chat 
        self.send_string_with_length(chat_user)
        #  Call this object instance method to send the message content to the server 
        self.send_string_with_length(message)

    #  Send refresh user list type 
    def send_refurbish_mark(self):
        #  Send refresh user list flag to server 
        self.client_socket.sendall(bytes("4", "utf-8"))

    # ===============  Encapsulate some methods of sending and receiving data  =================
    #  Send string with length 
    def send_string_with_length(self, content):
        #  The length of the content sent first 
        self.client_socket.sendall(bytes(content, encoding='utf-8').__len__().to_bytes(4, byteorder='big'))
        #  Then send the content 
        self.client_socket.sendall(bytes(content, encoding='utf-8'))

    #  Get the fixed length string from the server 
    def recv_string_by_length(self, len):
        return str(self.client_socket.recv(len), "utf-8")

    #  Get the variable length string from the server , In this case, the server will first pass a length value 
    def recv_all_string(self):
        length = int.from_bytes(self.client_socket.recv(4), byteorder='big')  #  Get message length 
        b_size = 3 * 1024  #  Be careful utf8 Chinese characters account for 3 byte , English 1 byte 
        times = math.ceil(length / b_size)
        content = ''
        for i in range(times):
            if i == times - 1:
                seg_b = self.client_socket.recv(length % b_size)
            else:
                seg_b = self.client_socket.recv(b_size)
            content += str(seg_b, encoding='utf-8')
        return content

    #  Get the number of online users sent by the server 
    def recv_number(self):
        return int.from_bytes(self.client_socket.recv(4), byteorder='big')

The above code is explained as follows :
stay chat_client The module construction method creates ==socket, There are also instance methods for sending different types of requests to the server , For example, landing. , Registration request , These instances just do the corresponding processing request , There are no messages sent or received directly to the server , Instead, the encapsulated send message and receive message instance methods are called separately , The advantage is that you can implement reusable code , You don't have to enter this code repeatedly in every request , In this way, we only need to enter a call statement in each processing instance

Be careful : The above code is for the client main Called , Running alone has no effect

client main modular

client main The main function of the module is to create corresponding interface objects , Handle user button events .
main.py

from tkinter import messagebox  #  Import prompt box 
import threading
import time
import tkinter.filedialog   #  Import file selection dialog module 
#  Import custom module 
import chat_register_panel
import chat_main_panel
import chat_login_panel
import chat_client

chat_user = "【 Group chat 】"  #  The global variable of life is group chat by default 

#  close socket function 
def close_socket():
    print(" Try disconnecting socket Connect ")
    #  Object call instance method close socoket
    client.client_socket.close()

#  Close the login interface function 
def close_login_window():
    close_socket()  #  Call close... Before closing socket function 
    login_frame.login_frame.destroy()  #  Object calls the instance method to close the login interface 

#  Close the chat interface function 
def close_main_window():
    #  Before closing, use the object to call the instance method to send the user exit sign to the server 
    client.send_message("exit", chat_user)
    close_socket()  #  Call off socket function 
    main_frame.main_frame.destroy()  # #  Object calls the instance method to close the login interface 

#  Open the file dialog box function , Used to add avatars 
def file_open_face():
    #  Open the file dialog 
    file_name = tkinter.filedialog.askopenfilename()
    #  If the path is not empty, read the picture and display it in the avatar 
    if file_name != '':
        #  Object calls the instance method to add the avatar 
        register_frame.add_face(file_name)
    else:
        messagebox.showwarning(title=" Tips ", message=" You haven't selected the file yet !")

#  Function for handling private chat 
def private_talk(self):
    global chat_user  #  Life global variables , Easy to use in other functions 
    #  Object uses instance variables , That is, the list component gets the index of the click 
    indexs = main_frame.friend_list.curselection()
    index = indexs[0]
    if index > 0:
        chat_user = main_frame.friend_list.get(index)  #  Get the clicked user name 
        #  Change the title name 
        if chat_user == '【 Group chat 】':  #  If the chat object is group chat , Set the following title 
            title = "  Online users  python Welcome to chat room :" + main_frame.user_name + " " + \
            " "
            main_frame.change_title(title)
        elif chat_user == main_frame.user_name:  #  If the user selects himself, the following dialog box will be prompted 
            messagebox.showwarning(title=" Tips ", message=" I can't talk to myself !")
            chat_user = '【 Group chat 】'  #  Change the chat object to group chat 
        else:  #  Otherwise, change to the following title 
            title = " " + main_frame.user_name + "  The private chat  -> " + chat_user + \
                    " "
            main_frame.change_title(title)

#  Login button event handling function 
def handding_login(self):
    #  call chat_login_pannel The object instance method of the module obtains the entered user name and password 
    user_name, password = login_frame.get_input()
    #  Judge that the user name and password cannot be empty 
    if user_name == "":
        messagebox.showwarning(title=" Tips ", message=" The username cannot be empty ")
        return
    if password == "":
        messagebox.showwarning(title=" Tips ", message=" The password cannot be empty ")
        return
    #  Call the... Created in this class chat_client Instance method of the object of the module , How to return True, Login succeeded 
    if client.login_type(user_name, password) == "1":
        go_to_main_panel(user_name)  #  Call this kind of function to the main chat interface , The parameter is the user name 
    else:
        messagebox.showwarning(title=" Tips ", message=" Wrong user name or password !")

#  Login interface registration button event handling function 
def handding_register():
    login_frame.close_login_panel()  #  Call the... Created in this class login_frame Object to close the login interface 
    global register_frame  #  Declare global variables , Easy to use in other functions 
    #  establish chat_register_panel The object of the module's registration interface , The function that closes the registration page and goes to the login interface close_register_window,
    #  Register button event function register_submi, Open the file dialog box and add the avatar function as a parameter 
    #  You can put chat_login_pannel The events of the module are bound to these functions 
    register_frame = chat_register_panel.RegisterPanel(file_open_face, close_register_window, register_submit)
    #  Call the instance method of the object to display the registration interface 
    register_frame.show_register_panel()
    register_frame.load()

#  Close the registration interface function 
def close_register_window():
    register_frame.close_register_panel()  #  Call the... Created in this class register_frame Object to close the registration interface 
    global login_frame  #  Use global variables , Can be used in other functions 
    #  establish chat_login_panel The object of the login interface of the module , Put this kind of login processing function handding_login,
    #  Register the processing function for handding_register, Close the login interface client socket Of close_login_window As a parameter 
    #  You can put chat_login_pannel The events of the module are bound to these functions 
    login_frame = chat_login_panel.LoginPanel(handding_login, handding_register, close_login_window)
    login_frame.show_login_panel()  #  Object calls the instance method of the chat main interface object 
    login_frame.load()  #  Call object instance method to load dynamic graph , And display interface 

#  The registration button of the registration interface handles the event function 
def register_submit(self):
    #  Call the object instance method created in this class to get the user name , password , Confirm the password , Avatar file path 
    user_name, password, confirm_password, file_name = register_frame.get_input()
    #  Judge user name , password , Confirm whether the password is empty 
    if user_name == "" or password == "" or confirm_password == "":
        messagebox.showwarning(" Can't be empty ", " Please complete the registration form ")
        return
    #  Judge whether the password is consistent with the confirmation password 
    if not password == confirm_password:
        messagebox.showwarning(" error ", " The two passwords are inconsistent ")
        return
    if register_frame.file_name == "":
        messagebox.showwarning(" error ", " Please select avatar !")
        return
    #  Object calls the instance method to send a message to the server 
    result = client.register_user(user_name, password, file_name)
    if result == "0":
        #  Registered successfully , Jump to the login interface 
        messagebox.showinfo(" success ", " Registered successfully ")
        close_register_window()  #  Call the function to close the registration page and go to the login interface 
    #  return 1 The user name is repeated 
    elif result == "1":
        #  repeat of user name 
        messagebox.showerror(" error ", " The user name has been registered ")
    #  Other mistakes 
    elif result == "2":
        #  Unknown error 
        messagebox.showerror(" error ", " An unknown error occurred ")

#  Send Message button event handling function 
def send_message(self):
    global chat_user
    print("send message:")
    #  Call the... Created in this class chat_main_panel The instance method of the object of the module obtains the sent content 
    content = main_frame.get_send_text()
    #  Judge whether the content is empty 
    if content == "" or content == "\n":
        messagebox.showwarning(title=" Tips ", message=" Empty message , Reject send ")
        return
    print(content)
    #  Call the... Created in this class chat_main_panel The instance method of the object of the module clears the contents of the input box 
    main_frame.clear_send_text()
    #  Call the... Created in this class chat_client The instance method of the object of the module sends chat content to the server 
    client.send_message(content, chat_user)

#  Send emoticon marker function 
def send_mark(exp):
    global chat_user #  Declare global variables 
    #  Call the... Created in this class chat_client The instance method of the object of the module sends the expression mark to the server 
    client.send_message(exp, chat_user)

#  Refresh user list button event handling function 
def refurbish_user():
    client.send_refurbish_mark()  #  Send refresh user list flag to server 

#  Close the login interface and go to the main interface 
def go_to_main_panel(user_name):
    login_frame.close_login_panel()  #  call login_frame Object to close the window 
    global main_frame  # #  Declare global variables , You can use... In other functions in your class 
    #  establish chat_main_panel Object of module , Put the user name , Send message function of this class , Send emoticon packet marker function ,
    #  Private chat function , Close the chat interface function as a parameter 
    #  You can put chat_main_panel The events of the module are bound to these functions 
    main_frame = chat_main_panel.MainPanel(user_name, send_message, send_mark, refurbish_user, private_talk, close_main_window)
    #  Create a sub thread specifically responsible for receiving and processing data 
    threading.Thread(target=recv_data).start()
    main_frame.show_main_panel()  #  Object calls the instance method of the chat main interface object to create the component layout 
    main_frame.load()  #  Call object instance method to load dynamic graph , And display the login interface 

#  Thread method for processing message reception 
def recv_data():
    #  Pause 1 second , When the main interface is rendered 
    time.sleep(1)
    while True:
        try:
            #  First, get the processing data type , And then deal with it accordingly 
            data_type = client.recv_all_string()  #  Call the object instance method to get the message sent by the server 
            print("recv type: " + data_type)
            #  Get the list of current online users 
            if data_type == "#!onlinelist#!":
                print(" Get online list data ")
                online_list = list()  #  Create a list to store users 
                online_number = client.recv_number()   #  Object calls the instance method to get the number of online users 
                for n in range(online_number):
                    #  Object gets the user name sent by the server every time it calls the instance method , And then add it to the list 
                    online_list.append(client.recv_all_string())
                #  Object calls the instance method to refresh the chat interface user online list 
                main_frame.refresh_friends(online_number, online_list)
                print(online_list)
            elif data_type == "#!message#!":
                print(" Get new message ")
                #  Call the object instance method to get the chat object sent by the server , And the user name 
                chat_flag = client.recv_all_string()
                user = client.recv_all_string()
                print("user: " + user)
                #  Call the object instance method to get the content sent by the server 
                content = client.recv_all_string()
                print("message: " + content)
                #  Object calls an instance method to display a message 
                main_frame.show_send_message(user, content, chat_flag)
        except Exception as e:
            print(" Error accepting server message , Message acceptance sub thread ends ." + str(e))
            break

#  Go to the login interface , At the same time, the function of opening the client port to connect to the server 
def go_to_login_panel():
    global client  #  Declare global variables , Can be used in other functions 
    client = chat_client.ChatSocket()  #  establish chat_client The client in the module connects to the server socket object 
    global login_frame #  Declare global variables , Can be used in other functions 
    #  establish chat_login_panel The object of the login interface of the module , Put this kind of login processing function handding_login,
    #  Register the processing function for handding_register, Close the login interface client socket in close_login_window Function as parameter 
    #  You can put chat_login_pannel The events of the module are bound to these functions 
    login_frame = chat_login_panel.LoginPanel(handding_login, handding_register, close_login_window)
    login_frame.show_login_panel()  #  Object calls the instance method of the chat main interface object to create components and layouts 
    login_frame.load()  #  Call the object instance method to load the dynamic diagram and display the interface 

#  entrance 
if __name__ == "__main__":
    go_to_login_panel()   #  Call the login interface function of this class 

So far, the module has given , above main Module is the main program , function main That's it , The premise is that the server chat_server Run first, otherwise an error will be reported .

A brief introduction main The execution process of the module :
When running main The module will run from the program entry first , That is to say, execute first go_to_login_panel function , This function first creates chat_client Modular ChatSocket object , Created at the same time as the object is created socket Connect to server , Then create chat_login_panel Module object display interface , The parameters are the two buttons of the interface to handle events and close the interface function , Other interfaces are similar .

copyright notice
author[stormzhuo],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/01/202201291229290392.html

Random recommended