Python课程-w73班
Louyj's Blog
Toggle navigation
Python课程-w73班
Home
班级课件
课堂代码
课后作业
学习资料
Archives
Tags
2022-06-19课堂代码
2022-06-19 09:25:55
8
0
0
python-w73
网络聊天室 服务端代码 ``` # 1. 服务器要有多个线程, 分别负责每个客户端 # 2. 客户端一个线程 ''' 功能: 1. 退出当前用户聊天窗口 (:unselect) 服务器阻塞点: recvfrom: 接受所有用户消息的, 当recvfrom阻塞时, 意味着所有客户端都没有消息过来 客户端阻塞点: 1. input等待用户输入, 阻塞时服务器推送消息就无法处理啦 2. 接收服务器消息: 消息类型: - 登录 - 聊天 - 退出 - 新用户上线 - 用户下线 xx={"type":"chat","to_user": "user01", "message":"xxxx"} xxx['key']=value {"type":"login","user": "user01"} python: {"type": True} json: {"type": true} 1. 实现用户登录功能 客户端: {"type":"login","user": "user01"} 服务器: 收到login消息->在线用户列表->所有用户发送用户上线消息 {"type":"online","new_user":"user001","all_users":{"user01":"127.0.0.1:8888"}} ''' import json import socket def encode_msg(msg): return json.dumps(msg).encode('utf-8') # dict->str->bytes def decode_msg(msg): return json.loads(msg.decode('utf-8')) # bytes->str->dict online_users = {} server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_socket.bind(('localhost', 8888)) while True: recv_message, recv_address = server_socket.recvfrom(1024) print("收到用户消息: %s, 网络地址: %s" % (recv_message, recv_address)) recv_message = decode_msg(recv_message) msg_type = recv_message['type'] if msg_type == 'login': recv_user = recv_message['user'] online_users[recv_user] = recv_address for user_name, address in online_users.items(): # [(k1,v1),(k2,v2),...] send_message = {'type': 'online', 'all_users': online_users, 'user': recv_user} server_socket.sendto(encode_msg(send_message), address) elif msg_type == 'offline': # 1. 用户列表里把下线用户删除掉 # 2. 向所有其他客户端发送用户下线通知 recv_user_name = recv_message['user'] del online_users[recv_user_name] for user_name, address in online_users.items(): if user_name != recv_user_name: send_message = {'type': 'offline', 'all_users': online_users, 'user': recv_user_name} server_socket.sendto(encode_msg(send_message), address) elif msg_type == 'chat': # 向'to_user'客户端转发消息 pass ``` 客户端代码 ``` import json import socket import threading def encode_msg(msg): return json.dumps(msg).encode('utf-8') # dict->str->bytes def decode_msg(msg): return json.loads(msg.decode('utf-8')) # bytes->str->dict def print_system_message(msg): print('\033[31m' + msg + '\033[0m') def receive(): global online_users while True: recv_message, recv_address = client_socket.recvfrom(1024) recv_message = decode_msg(recv_message) msg_type = recv_message['type'] if msg_type == 'online': online_users = recv_message['all_users'] print_system_message('系统消息: 新用户%s已上线' % recv_message['user']) elif msg_type == 'offline': # 1. 接收消息, 打印系统提示 {'type':'offline','user': '下线用户名','all_users':{所有用户}} online_users = recv_message['all_users'] print_system_message('系统消息: 用户%s已下线' % recv_message['user']) elif msg_type == 'chat': pass def send(): # 用户输入的分两种: 1: 指令 2. 聊天 while True: print("\033[31m>> \033[0m", end="") message = input() # 输入 if message == ':quit': # 1. 向服务器发送下线消息 {'type':'offline','user': '当前用户名'} # 2. 服务器向所有客户端发送消息提示: 系统消息: xxx已下线 send_message = {'type': 'quit', 'user': current_user_name} client_socket.sendto(encode_msg(send_message), server_address) print("系统退出") break elif message == ':user': print("=================在线用户列表=================") for user_name, address in online_users.items(): if user_name == current_user_name: print('用户: %s, 网络地址: %s:%s (*)' % (user_name, address[0], address[1])) else: print('用户: %s, 网络地址: %s:%s' % (user_name, address[0], address[1])) elif message == ':select': # 选择聊天用户 # 1. 在线用户列表 # 2. 提示用户输入聊天的用户名 # 3. 选中的 用户 用户名 要保存全局变量里面 # 1. 用户名必须存在, 且不能是自己 # 2. 选中的 用户 用户名 要保存全局变量里面, # 3. 打印提示符的时候要根据选择用户进行改变 pass else: # 聊天 # 聊天 :select :quit # 1. 判断有没有选择用户:v # 2. 向服务器发消息, json格式, {'type': 'chat','to_user': '聊天用户','message': '聊天消息'} pass online_users = {} current_selected_user = None # 已选中进行聊天的用户名 client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_address = ('localhost', 8888) print('欢迎使用在线聊天系统') current_user_name = input('请输入用户名: ') login_msg = {'type': 'login', 'user': current_user_name} client_socket.sendto(encode_msg(login_msg), server_address) threading.Thread(target=receive, daemon=True).start() threading.Thread(target=send).start() ''' 1. 序列化反序列化问题, 重用的地方封装成方法 2. 风格统一, 统一用json, 消息类型是多样的 3. 客户端改造成多线程, 接收线程/发送线程 \r系统提示 >> \r\n ''' ```
Pre:
2022-06-26课堂代码
Next:
2022-05-22课堂代码
0
likes
8
Weibo
Wechat
Tencent Weibo
QQ Zone
RenRen
Submit
Sign in
to leave a comment.
No Leanote account?
Sign up now.
0
comments
More...
Table of content
No Leanote account? Sign up now.