0


Python实现网络聊天室(支持多人聊天与私聊)

实验名称:

网络聊天室

功能:

i. 掌握利用Socket进行编程的技术
ii. 掌握多线程技术,保证双方可以同时发送
iii. 建立聊天工具
iv. 可以和单人聊天
v. 可以和多个人同时进行聊天
vi. 使用图形界面,显示双方的语录
vii. 程序可以在一定程度上进行错误识别

概述

实验通过聊天室可以完成单人或多人之间的聊天通信,功能的实现主要是通过Socket通信来实现。本次实验采用客户端/服务器(C/S)架构模式,通过Python语言来编写服务器端与客户端的程序。运用多线程可完成多点对多点的聊天。
服务器端程序主要用于接收用户信息,消息接收与转发。
客户端程序实现用户注册登录,聊天信息显示与信息输入。

代码解释

统计当前在线人数,并且将新用户加到用户列表中。
Serve.py
在这里插入图片描述
这是服务器对于聊天服务的实现。
在这里插入图片描述
通过继承threading.Thread类而实现多线程,重写run函数。在这里插入图片描述
接受来自客户端的用户名,如果用户名为空,使用用户的IP与端口作为用户名。如果用户名出现重复,则在出现的用户名依此加上后缀“2”、“3”、“4”……
在这里插入图片描述
在获取用户名后便会不断地接受用户端发来的消息(即聊天内容),结束后关闭连接。在这里插入图片描述
如果用户断开连接,将该用户从用户列表中删除,然后更新用户列表。在这里插入图片描述
将地址与数据(需发送给客户端)存入messages队列。在这里插入图片描述
服务端在接受到数据后,会对其进行一些处理然后发送给客户端,如下图,对于聊天内容,服务端直接发送给客户端,而对于用户列表,便由json.dumps处理后发送。

在这里插入图片描述
Client.py
建立连接,发送用户名及判断是否为私聊消息,私聊用~识别在这里插入图片描述
接受来自服务器发送的消息
在这里插入图片描述
对接收到的消息进行判断,如果是在线用户列表(用json.dumps处理过),便清空在线用户列表框,并将此列表输出在在线用户列表框中。

在这里插入图片描述
如果是聊天内容,便将其输出在聊天内容显示框中。
在这里插入图片描述
设置登录窗口

在这里插入图片描述
设置消息界面

在这里插入图片描述
设置在线用户列表。
在这里插入图片描述
完整代码:
Serve.py

import socket
import threading
import queue
import json  # json.dumps(some)打包   json.loads(some)解包import os
import os.path
import sys

IP ='127.0.0.1'
PORT =9999# 端口
messages = queue.Queue()
users =[]# 0:userName 1:connection
lock = threading.Lock()defonlines():# 统计当前在线人员
    online =[]for i inrange(len(users)):
        online.append(users[i][0])return online

classChatServer(threading.Thread):global users, que, lock

    def__init__(self):# 构造函数
        threading.Thread.__init__(self)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        os.chdir(sys.path[0])# 接受来自客户端的用户名,如果用户名为空,使用用户的IP与端口作为用户名。如果用户名出现重复,则在出现的用户名依此加上后缀“2”、“3”、“4”……defreceive(self, conn, addr):# 接收消息
        user = conn.recv(1024)# 用户名称
        user = user.decode()if user =='用户名不存在':
            user = addr[0]+':'+str(addr[1])
        tag =1
        temp = user
        for i inrange(len(users)):# 检验重名,则在重名用户后加数字if users[i][0]== user:
                tag = tag +1
                user = temp +str(tag)
        users.append((user, conn))
        USERS = onlines()
        self.Load(USERS,addr)# 在获取用户名后便会不断地接受用户端发来的消息(即聊天内容),结束后关闭连接。try:whileTrue:
                message = conn.recv(1024)# 发送消息
                message = message.decode()
                message = user +':'+ message
                self.Load(message,addr)
            conn.close()# 如果用户断开连接,将该用户从用户列表中删除,然后更新用户列表。except:   
            j =0# 用户断开连接for man in users:if man[0]== user:
                    users.pop(j)# 服务器段删除退出的用户break
                j = j+1

            USERS = onlines()
            self.Load(USERS,addr)
            conn.close()# 将地址与数据(需发送给客户端)存入messages队列。defLoad(self, data, addr):
        lock.acquire()try:
            messages.put((addr, data))finally:
            lock.release()# 服务端在接受到数据后,会对其进行一些处理然后发送给客户端,如下图,对于聊天内容,服务端直接发送给客户端,而对于用户列表,便由json.dumps处理后发送。defsendData(self):# 发送数据whileTrue:ifnot messages.empty():
                message = messages.get()ifisinstance(message[1],str):for i inrange(len(users)):
                        data =' '+ message[1]
                        users[i][1].send(data.encode())print(data)print('\n')ifisinstance(message[1],list):
                    data = json.dumps(message[1])for i inrange(len(users)):try:
                            users[i][1].send(data.encode())except:passdefrun(self):
        self.s.bind((IP,PORT))
        self.s.listen(5)
        q = threading.Thread(target=self.sendData)
        q.start()whileTrue:
            conn, addr = self.s.accept()
            t = threading.Thread(target=self.receive, args=(conn, addr))
            t.start()
        self.s.close()if __name__ =='__main__':
    cserver = ChatServer()
cserver.start()

Client.py

import socket
import tkinter
import tkinter.messagebox
import threading
import json
import tkinter.filedialog
from tkinter.scrolledtext import ScrolledText

IP =''
PORT =''
user =''
listbox1 =''# 用于显示在线用户的列表框
show =1# 用于判断是开还是关闭列表框
users =[]# 在线用户列表
chat ='------Group chat-------'# 聊天对象#登陆窗口

root0 = tkinter.Tk()
root0.geometry("300x150")
root0.title('用户登陆窗口')
root0.resizable(0,0)
one = tkinter.Label(root0,width=300,height=150,bg="LightBlue")
one.pack()

IP0 = tkinter.StringVar()
IP0.set('')
USER = tkinter.StringVar()
USER.set('')

labelIP = tkinter.Label(root0,text='IP地址',bg="LightBlue")
labelIP.place(x=20,y=20,width=100,height=40)
entryIP = tkinter.Entry(root0, width=60, textvariable=IP0)
entryIP.place(x=120,y=25,width=100,height=30)

labelUSER = tkinter.Label(root0,text='用户名',bg="LightBlue")
labelUSER.place(x=20,y=70,width=100,height=40)
entryUSER = tkinter.Entry(root0, width=60, textvariable=USER)
entryUSER.place(x=120,y=75,width=100,height=30)defLogin(*args):global IP, PORT, user
    IP, PORT = entryIP.get().split(':')
    user = entryUSER.get()ifnot user:
        tkinter.messagebox.showwarning('warning', message='用户名为空!')else:
        root0.destroy()

loginButton = tkinter.Button(root0, text ="登录", command = Login,bg="Yellow")
loginButton.place(x=135,y=110,width=40,height=25)
root0.bind('<Return>', Login)

root0.mainloop()# 建立连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((IP,int(PORT)))if user:
    s.send(user.encode())# 发送用户名else:
    s.send('用户名不存在'.encode())
    user = IP +':'+ PORT

# 聊天窗口
root1 = tkinter.Tk()
root1.geometry("640x480")
root1.title('群聊')
root1.resizable(0,0)# 消息界面
listbox = ScrolledText(root1)
listbox.place(x=5, y=0, width=640, height=320)
listbox.tag_config('tag1', foreground='red',backgroun="yellow")
listbox.insert(tkinter.END,'欢迎进入群聊,大家开始聊天吧!','tag1')

INPUT = tkinter.StringVar()
INPUT.set('')
entryIuput = tkinter.Entry(root1, width=120, textvariable=INPUT)
entryIuput.place(x=5,y=320,width=580,height=170)# 在线用户列表
listbox1 = tkinter.Listbox(root1)
listbox1.place(x=510, y=0, width=130, height=320)defsend(*args):
    message = entryIuput.get()+'~'+ user +'~'+ chat
    s.send(message.encode())
    INPUT.set('')

sendButton = tkinter.Button(root1, text ="\n发\n\n\n送",anchor ='n',command = send,font=('Helvetica',18),bg ='white')
sendButton.place(x=585,y=320,width=55,height=300)
root1.bind('<Return>', send)defreceive():global uses
    whileTrue:
        data = s.recv(1024)
        data = data.decode()print(data)try:
            uses = json.loads(data)
            listbox1.delete(0, tkinter.END)
            listbox1.insert(tkinter.END,"当前在线用户")
            listbox1.insert(tkinter.END,"------Group chat-------")for x inrange(len(uses)):
                listbox1.insert(tkinter.END, uses[x])
            users.append('------Group chat-------')except:
            data = data.split('~')
            message = data[0]
            userName = data[1]
            chatwith = data[2]
            message ='\n'+ message
            if chatwith =='------Group chat-------':# 群聊if userName == user:
                    listbox.insert(tkinter.END, message)else:
                    listbox.insert(tkinter.END, message)elif userName == user or chatwith == user:# 私聊if userName == user:
                    listbox.tag_config('tag2', foreground='red')
                    listbox.insert(tkinter.END, message,'tag2')else:
                    listbox.tag_config('tag3', foreground='green')
                    listbox.insert(tkinter.END, message,'tag3')

            listbox.see(tkinter.END)
r = threading.Thread(target=receive)
r.start()# 开始线程接收信息

root1.mainloop()
s.close()

听取了大家的意见,我来加以下我当时的运行截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
整体的报告在这里,大家有需要自取~
链接:https://pan.baidu.com/s/1FzK3rociAE_4pwfwKCvYqQ
提取码:2580

标签: 经验分享

本文转载自: https://blog.csdn.net/weixin_43916997/article/details/110761676
版权归原作者 阿迪不想上班 所有, 如有侵权,请联系我们删除。

“Python实现网络聊天室(支持多人聊天与私聊)”的评论:

还没有评论