实验名称:
网络聊天室
功能:
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
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()
def onlines(): # 统计当前在线人员
online = []
for i in range ( len (users)):
online.append(users[i][ 0 ])
return online
class chatserver(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”……
def receive( self , conn, addr): # 接收消息
user = conn.recv( 1024 ) # 用户名称
user = user.decode()
if user = = '用户名不存在' :
user = addr[ 0 ] + ':' + str (addr[ 1 ])
tag = 1
temp = user
for i in range ( 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 :
while true:
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队列。
def load( self , data, addr):
lock.acquire()
try :
messages.put((addr, data))
finally :
lock.release()
# 服务端在接受到数据后,会对其进行一些处理然后发送给客户端,如下图,对于聊天内容,服务端直接发送给客户端,而对于用户列表,便由json.dumps处理后发送。
def senddata( self ): # 发送数据
while true:
if not messages.empty():
message = messages.get()
if isinstance (message[ 1 ], str ):
for i in range ( len (users)):
data = ' ' + message[ 1 ]
users[i][ 1 ].send(data.encode())
print (data)
print ( '\n' )
if isinstance (message[ 1 ], list ):
data = json.dumps(message[ 1 ])
for i in range ( len (users)):
try :
users[i][ 1 ].send(data.encode())
except :
pass
def run( self ):
self .s.bind((ip,port))
self .s.listen( 5 )
q = threading.thread(target = self .senddata)
q.start()
while true:
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
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 )
def login( * args):
global ip, port, user
ip, port = entryip.get().split( ':' )
user = entryuser.get()
if not 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 )
def send( * 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)
def receive():
global uses
while true:
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 in range ( 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()
|
到此这篇关于python实现网络聊天室的示例代码(支持多人聊天与私聊)的文章就介绍到这了,更多相关python 网络聊天室内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/weixin_43916997/article/details/110761676