找回密码
 会员注册
查看: 28|回复: 0

基于PythonguI的多人聊天室的设计与实现

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64454
发表于 2024-9-11 13:11:14 | 显示全部楼层 |阅读模式
基于PythonguI的多人聊天室的设计与实现 摘要现在,即时聊天系统已成为Internet上的主要交流工具,并且涌现出大量的AP和平台。这些AP和平台都拥有更加完善的交换机制,使得人们可以更加便捷地进行沟通和交换信息。广域网的聊天系统多重多样,知名的软件主要有Facebook、腾讯QQ等。局域网聊天通信软件也有很多,最著名的应该是飞秋。为了学习和应用Windows网络通信编程,我们学习了相关知识,为了应用实践,使用网络通信中的TCP和UDP编程,实现了多人在线聊天系统。这个项目旨在提供一个便捷的、高效的社交空间,它利用python的tkinter、threading、soket等多线程库,可以轻松地建立起一个多种社交模式,既可以进行群组交流,也可以进行个人私信,甚至可以发布表情包。该项目由两个部件组成:一个是服务器,负责处理所有的数据。另一个是通讯设备,负责处理所有的文件。两个部件都使用Tcp协议来实现互联互通。关键词多人聊天室;Soket;tcp;python目录1、引言1.1背景和意义1.2系统要实现的功能1.2.1用户登录1.2.2群发消息1.2.3一对一聊天1.2.4发送表情2、系统结构2.1系统结构图2.2系统实现原理2.2.1服务器端实现原理2.2.2客户端实现原理2.3系统技术分析2.3.1tkinter图形用户界面库2.3.2threading多线程2.3.3socket网络编程3、实现代码3.1服务器端代码3.1.1确定全局变量3.1.2实现多线程接收数据3.1.3处理接收到的数据3.1.4将在线用户存入online列表并返回3.1.5删除用户3.1.6发送消息3.1.7主函数3.2客户端代码3.2.1确定全局变量3.2.2登录窗口实现3.2.4创建聊天窗口3.2.5发送数据3.2.6 实现私聊3.2.7接收数据并打印3.2.8主函数4、实验结果4.1用户登录4.2群发消息4.3一对一聊天4.4发送表情5、总结和展望5.1项目总结5.2项目展望参考文献致  谢附  录1、引言1.1背景和意义        随着互联网时代的到来,人与人之间的联系更加紧密。在现实生活中需要一个契机才有机会进行深入的沟通,人们对彼此的了解仅仅是浅层的,而在线的聊天则可以让我们抛开一切外在的东西,用语言去了解一个人的内在。1.2系统要实现的功能1.2.1用户登录用户使用默认的服务器端口地址,输入昵称,接着点击‘登录’按钮,实现登录聊天系统。1.2.2群发消息点击列表,然后选择点击消息中的群发,写好想发的消息后点发送按钮就可以群发消息。1.2.3一对一聊天点击列表,然后选择点击消息中的对象,选择好想要发送的人,此,写好想发的消息后点击发送按钮就可以对当前那个人一对一的去聊天。1.2.4发送表情用户点击‘表情’按钮,此时点击需要发送的表情即可发送2、系统结构2.1系统结构图        分成了服务端与客户端,选择采用Tcp协议传输数据与网络。存储用户连接的信息在于服务器,包括用户的IP地址、端口、用户信息等。2.2系统实现原理系统采用C/S模式进行实现2.2.1服务器端实现原理        登录和接收数据实现原理:采用tcp协议,对自己定义的端口进行监听,监听到有新的端口,就会创造出新的出来。        发送数据实现原理:启动服务器后,新建一个线程,检查消息队列中的数据是否为空,如果不为空,则调用发送数据函数等。2.2.2客户端实现原理        数据传输实现原理:客户数据以(消息内容:;当前用户:;目标用户)的形式发送给服务器,服务器将消息转发给目标用户。        数据接收执行原理:客户端接收到数据后,分析数据判断是否为笑脸信息,如果是则搜索笑脸词对应的图片显示在聊天信息中;如果不是笑脸消息smileymessage,则该消息会直接显示在聊天消息中。2.3系统技术分析2.3.1tkinter图形用户界面库        Tkinter:一种基于Python的TkGUI界面,它的Tkinter接口为大多数Unix、Windows、Macintosh等操作环境提供了一种便捷的界面,从而大大提高了编程的效率。Tk8.0的更新版能够提供更加逼真的本地窗体体验,而且能够轻松适用于大多数AP。2.3.2threading多线程        ​所有的线程均拥有一组CPU寄存器,这些寄存器构成一条记录着它们之前在某一时刻的操作的路径,从而构成一条完整的路径。        指令指针与堆栈指针寄存器被认为是处理单个线程的关键设备,它们可以指示单个线程的位置,并且可以帮助单个线程更好的理解单个线程的功能。2.3.3socket网络编程 ython为用户带来两种不同等级的互联互通功能。网络服务的低端版本通常只支持Socket,但也可以使用标准的BSDSockets来实现高级功能。通过Socket接口,用户可以获取到底层操作系统的所有功能。SocketServer是一种先进且功能强大的网络服务模块,其能够为用户节省大量时间和资源,从而大大降低网络架构设计成本。Socket,也被称为"套接字",是一种通信技术,它能够让不同的主机或单台计算机之间的进程之间实现有效的连接,从而实现"套接字"的请求和响应。在Python中,socket()是一种常见的连接方式,它可以帮助构造出复杂的连接字。socket.socket([family[,type[,proto]]])​参数:family:通过将AF_UNIX和AF_INET连接起来,我们能够创建一个family。type:套接字的类型可以根据它们的用途来划分,有些是用于连接,而有些则是用于非连接。​protocol:一般不填默认为0.3、实现代码3.1服务器端代码3.1.1确定全局变量IP=''PORT=80808Errque=errqueue.eeeQueue()          usersewrew =[ewe] [weceweonn,ewewuser,eweweaddr]ewelocewewk=thwewereading.Lewwewock()      3.1.2实现多线程接收数据classChatServer(threading.Thread):    def__init__(self,port):        threading.Thread.__init__(self)        self.ADDR=('',port)        self.s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #用于接收所有客户端发送信息的函数    deftcp_connect(self,conn,addr):    pass;    #每当接收到一个socket连接就为其创建并启动一个新的线程    defrun(self):        self.s.bind(self.ADDR)        self.s.listen(5)        print('服务器正在运行中...')        q=threading.Thread(target=self.sendData)        q.start()        whileTrue:            conn,addr=self.s.accept()            t=threading.Thread(target=self.tcp_connect,args=(conn,addr))            t.start()        self.s.close()3.1.3处理接收到的数据# 将接收到的信息(ip,端口以及发送的信息)存入que队列defrecv(self,data,addr):    lock.acquire()    try:        que.put((addr,data))    finally:        lock.release()#用于接收所有客户端发送信息,并将数据保存到消息队列中deftcp_connect(self,conn,addr):    #连接后将用户信息添加到users列表    user=conn.recv(1024)                #接收用户名    user=user.decode()    foriinrange(len(users)):        ifuser==users[i][1]:            print('Useralreadyexist')            user=''+user+'_2'    ifuser=='no':        user=addr[0]+':'+str(addr[1])    users.append((conn,user,addr))    print('新的连接:',addr,':',user,end='')        #打印用户名    d=onlines()                 #有新连接则刷新客户端的在线用户显示    self.recv(d,addr)    try:        whileTrue:            data=conn.recv(1024)            data=data.decode()            self.recv(data,addr)                        #保存信息到队列        conn.close()    except:        print(user+'断开连接')        self.delUsers(conn,addr)                    #将断开用户移出users        conn.close()3.1.4将在线用户存入online列表并返回defonlines():    online=[]    foriinrange(len(users)):        online.append(users[i][1])    returnonline3.1.5删除用户 #判断断开用户在users中是第几位并移出列表,刷新客户端的在线用户显示defdelUsers(self,conn,addr):    a=0    foriinusers:        ifi[0]==conn:            users.pop(a)            print('在线用户:',end='')      #打印剩余在线用户(conn)            d=onlines()            self.recv(d,addr)            print(d)                break            a+=13.1.6发送消息#将队列que中的消息发送给所有连接到的用户defsendData(self):    whileTrue:        ifnotque.empty():            data=''            reply_text=''            message=que.get()                              #取出队列第一个元素            ifisinstance(message[1],str):                  #如果data是str则返回Ture                foriinrange(len(users)):                    #user[i][1]是用户名,users[i][2]是addr,将message[0]改为用户名                    forjinrange(len(users)):                        ifmessage[0]==users[j][2]:                            print('this:messageisfromuser[{}]'.format(j))                            data=''+users[j][1]+':'+message[1]                            break                    users[i][0].send(data.encode())            #data=data.split(':;')[0]            ifisinstance(message[1],list): #同上                #如果是list则打包后直接发送                 data=json.dumps(message[1])                foriinrange(len(users)):                    try:                        users[i][0].send(data.encode())                    except:                        pass3.1.7主函数#监听服务器线程是否处于运行状态if__name__=='__main__':    cserver=ChatServer(PORT)    cserver.start()    whileTrue:        time.sleep(1)        ifnotcserver.isAlive():            print("Chatconnectionlost...")            sys.exit(0)3.2客户端代码3.2.1确定全局变量IP=''PORT=''user=''listbox1='' #用于显示在线用户的列表框ii=0 #用于判断是开还是关闭列表框users=[] #在线用户列表chat='【群发】' #聊天对象,默认为群聊3.2.2登录窗口实现#登陆窗口loginRoot=tkinter.Tk()loginRoot.title('聊天室')loginRoot['height']=110loginRoot['width']=270loginRoot.resizable(0,0) #限制窗口大小IP1=tkinter.StringVar()IP1.set('127.0.0.1:8888') #默认显示的ip和端口User=tkinter.StringVar()User.set('')#服务器标签labelIP=tkinter.Label(loginRoot,text='地址:端口')labelIP.place(x=20,y=10,width=100,height=20)entryIP=tkinter.Entry(loginRoot,width=80,textvariable=IP1)entryIP.place(x=120,y=10,width=130,height=20)#用户名标签labelUser=tkinter.Label(loginRoot,text='昵称')labelUser.place(x=30,y=40,width=80,height=20)entryUser=tkinter.Entry(loginRoot,width=80,textvariable=User)entryUser.place(x=120,y=40,width=130,height=20)#登录按钮deflogin(*args):    globalIP,PORT,user    IP,PORT=entryIP.get().split(':') #获取IP和端口号    ORT=int(PORT)                    #端口号需要为int类型    user=entryUser.get()    ifnotuser:        tkinter.messagebox.showerror('温馨提示',message='请输入任意的用户名!')    else:        loginRoot.destroy()                 #关闭窗口loginRoot.bind('',login)           #回车绑定登录功能but=tkinter.Button(loginRoot,text='登录',command=login)but.place(x=100,y=70,width=70,height=30)loginRoot.mainloop()3.2.3与服务器建立连接s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)s.connect((IP,PORT))ifuser:    s.send(user.encode()) #发送用户名else:    s.send('no'.encode()) #没有输入用户名则标记no3.2.4创建聊天窗口#聊天窗口#创建图形界面root=tkinter.Tk()root.title(user) #窗口命名为用户名root['height']=400root['width']=580root.resizable(0,0) #限制窗口大小#创建多行文本框listbox=ScrolledText(root)listbox.place(x=5,y=0,width=570,height=320)#文本框使用的字体颜色listbox.tag_config('red',foreground='red')listbox.tag_config('blue',foreground='blue')listbox.tag_config('green',foreground='green')listbox.tag_config('pink',foreground='pink')listbox.insert(tkinter.END,'欢迎加入聊天室!','blue')#创建多行文本框,显示在线用户listbox1=tkinter.Listbox(root)listbox1.place(x=445,y=0,width=130,height=320)defshowUsers():    globallistbox1,ii    ifii==1:        listbox1.place(x=445,y=0,width=130,height=320)        ii=0    else:        listbox1.place_forget() #隐藏控件        ii=1#查看在线用户按钮button1=tkinter.Button(root,text='用户列表',command=showUsers)button1.place(x=485,y=320,width=90,height=30)#创建输入文本框和关联变量a=tkinter.StringVar()a.set('')entry=tkinter.Entry(root,width=120,textvariable=a)entry.place(x=5,y=350,width=570,height=40)3.2.5发送数据defsend(*args):    #没有添加的话发送信息时会提示没有聊天对象    users.append('【群发】')    print(chat)    ifchatnotinusers:        tkinter.messagebox.showerror('温馨提示',message='没有聊天对象!')        return    ifchat==user:        tkinter.messagebox.showerror('温馨提示',message='自己不能和自己进行对话!')        return    mes=entry.get()+':;'+user+':;'+chat #添加聊天对象标记    s.send(mes.encode())a.set('') #发送后清空文本框3.2.6 实现私聊#创建发送按钮button=tkinter.Button(root,text='发送',command=send)button.place(x=515,y=353,width=60,height=30)    globalchat    #获取点击的索引然后得到内容(用户名)    indexs=listbox1.curselection()    index=indexs[0]    ifindex>0:        chat=listbox1.get(index)        #修改客户端名称        ifchat=='【群发】':            root.title(user)            return        ti=user+' --> '+chat        root.title(ti)#在显示用户列表框上设置绑定事件listbox1.bind('',private)3.2.7接收数据并打印deftreceev():    ttglobaltusers    eerwhierleTrerrue:        daereta=rerrs.recv(1024)        daereta=daerreta.derecoerede()               try:            data=json.loads(data)            useerrrs=data            rereliserertbox1.delete(0,tkererinter.END) #清空列表框            nurreerererermber=(' errer 在线用户数:'+str(len(data)))            ererliserertbox1.insert(tkirenter.ErerND,numbrererr)            listbox1.itemconfig(tkinter.END,fg='green',bg="#f0f0ff")            listbox1.insert(tkinter.END,'【群发】')            listbox1.itemconfig(tkinter.END,fg='green')            foriinrange(len(data)):                listbox1.insert(tkinter.END,(data[i]))                listbox1.itemconfig(tkinter.END,fg='green')        except:            data=data.split(':;')            data1=data[0].strip() #消息            data2=data[1] #发送信息的用户名            data3=data[2] #聊天对象            markk=data1.split(':')[1]            #判断是不是图片            pic=markk.split('#')            #判断是不是表情            #如果字典里有则贴图            if(markkindic)orpic[0]=='``':                data4='\n'+data2+':' #例:名字->\n名字:                ifdata3=='【群发】':                    ifdata2==user: #如果是自己则将则字体变为蓝色                        listbox.insert(tkinter.END,data4,'blue')                    else:                        listbox.insert(tkinter.END,data4,'green') #END将信息加在最后一行                elifdata2==userordata3==user: #显示私聊                    listbox.insert(tkinter.END,data4,'red') #END将信息加在最后一行                listbox.image_create(tkinter.END,image=dic[markk])            else:                data1='\n'+data1                ifdata3=='【群发】':                    ifdata2==user: #如果是自己则将则字体变为蓝色                        listbox.insert(tkinter.END,data1,'blue')                    else:                        listbeeox.insereeet(tkeeinter.END,datea1,'gereene') #END将信息加在最后一行3.2.8主函数Tee =ssertto.starteee() #开始线程接收信息root.mainloop()s.close() #关闭图形界面后关闭TCP连接4、实验结果4.1用户登录        用户只需要输入自己的昵称,并且使用默认的服务器端口地址,点击‘登录’按钮,就能够轻松访问聊天系统,如图1所示: 图1用户登录4.2群发消息        找到列表,点击群发就可以群发消息,以群发消息为例: 图2 群发消息4.3一对一聊天        点击那个列表就可以看到,发送这个,然后发送对象,聊天的窗口对目标的用户,点击发消息就可以对一个人来聊天了,以我自己群发消息给为例,如图所示 图3 一对一聊天4.4发送表情        用户点击‘表情’按钮,如图所示,此时点击表情即可发送。 图4 发送表情5、总结和展望5.1项目总结这个项目旨在提供一个便捷的、高效的社交空间,它利用python的tkinter、threading、soket等多线程库,可以轻松地建立起一个多种社交模式,既可以进行群组交流,也可以进行个人私信,甚至可以发布表情包。该项目由两个部件组成:一个是服务器,负责处理所有的数据。另一个是通讯设备,负责处理所有的文件。两个部件都使用Tcp协议来实现互联互通。5.2项目展望本项目实现了基本的聊天功能,后期将会加入的功能有,语音聊天、视屏聊天、文件共享等。参考文献[1]《信息与电脑》|2013年第008期|7-8,10-11|共4页张海文;2022-08-18[2]沈健程瑞龙 《移动信息》2022年第9期0028-0030,共3页[3](美)[弗格森]DerekFerguson著.JSP程序调试实用手册[M].电子工业出版社,2001.62~87[4]《电脑知识与技术:学术版》|2022年第5期|61-63|共3页袁明坤;曾丽;2022-9-15[5]谢希仁.计算机网络[M].北京:电子工业出版社,2004。[6]W.RichardStevens.TCP/IP详解[M].北京:机械工业出版社,2005。[7]张炯.Unix网络编程[M].北京:清华大学出版社,2002。[8]求是科技,王正军.VisualC++6.0从入门到精通[M].北京:人民邮电出版社,2006。[9]孙鑫,余安萍.VC++深入详解[M].北京:电子工业出版社,2006。[10]陈坚,陈伟.VisualC++网络高级编程[M].北京:人民邮电出版社,2001。[11]吴志军.VisualC++视频会议开发技术与实例[M].北京:人民邮电出版社,2006。致  谢感谢指导老师对指导我,起到了很大的帮助作用。感谢他分享的学习成果,使我在学习及技术上少走弯路,使我的学习上更进一步。同时感谢我的父母,他们在论文期间与我交流,分担我的心理压力,在日常生活中给予我帮助,在学习精神上鼓励我。最后,向这群心甘情愿帮助我的人表示感谢和衷心的感谢。附  录聊天窗口创建图形界面root=tkinter.Tk()root.title(user) #窗口命名为用户名root['height']=400root['width']=580root.resizable(0,0) #限制窗口大小#创建多行文本框listbox=ScrolledText(root)listbox.place(x=5,y=0,width=570,height=320)#文本框使用的字体颜色listbox.tag_config('red',foreground='red')listbox.tag_config('blue',foreground='blue')listbox.tag_config('green',foreground='green')listbox.tag_config('pink',foreground='pink')listbox.insert(tkinter.END,'欢迎加入聊天室!','blue')#创建多行文本框,显示在线用户listbox1=tkinter.Listbox(root)listbox1.place(x=445,y=0,width=130,height=320)defshowUsers():    globallistbox1,ii    ifii==1:        listbox1.place(x=445,y=0,width=130,height=320)        ii=0    else:        listbox1.place_forget() #隐藏控件        ii=1#查看在线用户按钮button1=tkinter.Button(root,text='用户列表',command=showUsers)button1.place(x=485,y=320,width=90,height=30)#创建输入文本框和关联变量a=tkinter.StringVar()a.set('')entry=tkinter.Entry(root,width=120,textvariable=a)entry.place(x=5,y=350,width=570,height=40)此论文维普查重已过,23年做的,详细资料可以关注私信我,Python,Java,php,html,c语言,微信小程序,APP,安卓,物联网等毕业设计都可找我。请关注点赞+私信博主,领取项目源码关注博主下篇更精彩一键三连!!!一键三连!!!一键三连!!!感谢一键三连!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-28 08:04 , Processed in 0.421379 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表