实验名称:
网络聊天室
功能:
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() 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
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()
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]