标签:erro ocs 实现 基类 检查 用户名 desc 异常 发送消息
英文捉鸡点 这里
源码中可以看到其实本质上就对 select 以及 socket 的进一步封装
Python的asyncore模块提供了以异步的方式写入套接字服务的客户端和服务器的基础结构。
英捉鸡 , 这里
该模块建立在asyncore
基础架构之上,简化了异步客户端和服务器,并且更容易处理元素被任意字符串终止或者长度可变的协议。
本次项目开发所需要用到的模块和接口
用于创建 server_socket 套接字
整体操作类似于 socket 的使用
import asynchat import asyncore # 定义端口 PORT = 6666 # 定义结束异常类 class EndSession(Exception): pass class ChatServer(asyncore.dispatcher): """ 聊天服务器 """ def __init__(self, port): asyncore.dispatcher.__init__(self) # 创建socket self.create_socket() # 设置 socket 为可重用 self.set_reuse_addr() # 监听端口 self.bind((‘‘, port)) self.listen(5) self.users = {} self.main_room = ChatRoom(self) def handle_accept(self): conn, addr = self.accept() ChatSession(self, conn)
用于维护聊天室
重写了 collect_incoming_data 用于数据存放
以及 found_terminator 来进行结束标志
以及 handle_close 来进行结束操作
class ChatSession(asynchat.async_chat): """ 负责和客户端通信 """ def __init__(self, server, sock): asynchat.async_chat.__init__(self, sock) self.server = server self.set_terminator(b‘\n‘) self.data = [] self.name = None self.enter(LoginRoom(server)) def enter(self, room): # 从当前房间移除自身,然后添加到指定房间 try: cur = self.room except AttributeError: pass else: cur.remove(self) self.room = room room.add(self) def collect_incoming_data(self, data): # 接收客户端的数据 self.data.append(data.decode("utf-8")) def found_terminator(self): # 当客户端的一条数据结束时的处理 line = ‘‘.join(self.data) self.data = [] try: self.room.handle(self, line.encode("utf-8")) # 退出聊天室的处理 except EndSession: self.handle_close() def handle_close(self): # 当 session 关闭时,将进入 LogoutRoom asynchat.async_chat.handle_close(self) self.enter(LogoutRoom(self.server))
用于自定义协议, 类似于开发 httpserver 的时候的 协议格式定制处理
我们预设了4种命令分别由 其同名函数进行分发处理
class CommandHandler: """ 命令处理类 """ def unknown(self, session, cmd): # 响应未知命令 # 通过 asynchat.async_chat.push 方法发送消息 session.push((‘Unknown command {} \n‘.format(cmd)).encode("utf-8")) def handle(self, session, line): line = line.decode() # 命令处理 if not line.strip(): return parts = line.split(‘ ‘, 1) cmd = parts[0] try: line = parts[1].strip() except IndexError: line = ‘‘ # 通过协议代码执行相应的方法 method = getattr(self, ‘do_‘ + cmd, None) try: method(session, line) except TypeError: self.unknown(session, cmd)
Room 类继承了 CommandHandler 可以处理聊天室中的命令处理
主要用于维护一个存有所有用户的 sessions 列表以及 广播发送信息处理
class Room(CommandHandler): """ 包含多个用户的环境,负责基本的命令处理和广播 """ def __init__(self, server): self.server = server self.sessions = [] def add(self, session): # 一个用户进入房间 self.sessions.append(session) def remove(self, session): # 一个用户离开房间 self.sessions.remove(session) def broadcast(self, line): # 向所有的用户发送指定消息 # 使用 asynchat.asyn_chat.push 方法发送数据 for session in self.sessions: session.push(line) def do_logout(self, session, line): # 退出房间 raise EndSession
用户登录后需要广播一条信息 xxx 加入聊天室
class LoginRoom(Room): """ 处理登录用户 """ def add(self, session): # 用户连接成功的回应 Room.add(self, session) # 使用 asynchat.asyn_chat.push 方法发送数据 session.push(b‘Connect Success‘) def do_login(self, session, line): # 用户登录逻辑 name = line.strip() # 获取用户名称 if not name: session.push(b‘UserName Empty‘) # 检查是否有同名用户 elif name in self.server.users: session.push(b‘UserName Exist‘) # 用户名检查成功后,进入主聊天室 else: session.name = name session.enter(self.server.main_room)
class LogoutRoom(Room): """ 处理退出用户 """ def add(self, session): # 从服务器中移除 try: del self.server.users[session.name] except KeyError: pass
class ChatRoom(Room): """ 聊天用的房间 """ def add(self, session): # 广播新用户进入 session.push(b‘Login Success‘) self.broadcast((session.name + ‘ has entered the room.\n‘).encode("utf-8")) self.server.users[session.name] = session Room.add(self, session) def remove(self, session): # 广播用户离开 Room.remove(self, session) self.broadcast((session.name + ‘ has left the room.\n‘).encode("utf-8")) def do_say(self, session, line): # 客户端发送消息 self.broadcast((session.name + ‘: ‘ + line + ‘\n‘).encode("utf-8")) def do_look(self, session, line): # 查看在线用户 session.push(b‘Online Users:\n‘) for other in self.sessions: session.push((other.name + ‘\n‘).encode("utf-8"))
if __name__ == ‘__main__‘: s = ChatServer(PORT) try: print("chat server run at ‘0.0.0.0:{0}‘".format(PORT)) asyncore.loop() except KeyboardInterrupt: print("chat server exit")
pass
初始状态
用户操作
To build a functioning async_chat subclass your input methods collect_incoming_data() and found_terminator() must handle the data that the channel receives asynchronously. The methods are described below
标签:erro ocs 实现 基类 检查 用户名 desc 异常 发送消息
原文地址:https://www.cnblogs.com/shijieli/p/10662419.html