Python基础教程之虚拟茶话会程序分析
来源:互联网 发布:淘宝小智 编辑:程序博客网 时间:2024/05/21 05:17
本程序需要windows 的telnet客户端支持,在windows7下telnet客户端是默认关闭的。如何打开它请参考http://jingyan.baidu.com/article/2fb0ba4055e55800f3ec5f7a.html
具体程序如下:
from asyncore import dispatcherfrom asynchat import async_chatimport socket, asyncorePORT = 5005NAME = 'TestChat'class EndSession(Exception): passclass CommandHandler(object): def unknown(self, session, cmd): session.push('Unknown command: %s\r\n' % cmd) def handle(self, session, line): if not line.strip(): return parts = line.split(' ', 1) cmd = parts[0] try: line = parts[1].strip() except IndexError: line = '' meth = getattr(self, 'do_' + cmd, None) try: meth(session, line) except TypeError: self.unknown(session, cmd)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): for session in self.sessions: session.push(line) def do_logout(self, session, line): raise EndSessionclass LoginRoom(Room): def add(self, session): Room.add(self, session) self.broadcast('Welcome to %s\r\n' % self.server.name) def unknow(self, session, cmd): session.push('Plz log in \nUse "login <nick>"\r\n') def do_login(self, session, line): name = line.strip() if not name: session.push('Plz enter a name\r\n') elif name in self.server.users: session.push('The name "%s" is taken.\r\n' % name) session.push('Plz try again.\r\n') else: session.name = name session.enter(self.server.main_room)class ChatRoom(Room): def add(self, session): self.broadcast(session.name + ' has entered the room.\r\n') 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.\r\n') def do_say(self, session, line): self.broadcast(session.name + ': ' + line + '\r\n') def do_look(self, session, line): session.push('The following are in this room\r\n') for other in self.sessions: session.push(other.name + '\r\n') def do_who(self, session, line): session.push('The following are logged in: \r\n') for name in self.server.users: session.push(name + '\r\n')class LogoutRoom(Room): def add(self, session): try: del self.server.users[session.name] except KeyError: passclass ChatSession(async_chat): def __init__(self, server, sock): async_chat.__init__(self, sock) self.server = server self.set_terminator('\r\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) def found_terminator(self): line = ''.join(self.data) self.data = [] try: self.room.handle(self, line) except EndSession: self.handle_close() def handle_close(self): async_chat.handle_close(self) self.enter(LogoutRoom(self.server))class ChatServer(dispatcher): def __init__(self, port, name): dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind(('', port)) self.listen(5) self.name = name self.users = {} self.main_room = ChatRoom(self) def handle_accept(self): conn, addr = self.accept() ChatSession(self, conn)if __name__ == '__main__': s = ChatServer(PORT, NAME) try: asyncore.loop() except KeyboardInterrupt: print
对于charserver.py程序其构成思路是
ChatServer类(服务器类):负责侦听和连接响应
ChatRoom类(聊天房间类):负责用户管理
ChatSession类(聊天接口类):负责接收客户端发来的程序。
当有连接进入时,chatserver类将建立对应的ChatSession实例,该实例初始化过程包含:
1.初始化一些配置,如聊天语句终止符设立(必须)
2.给某些变变量赋值:包括该会话属于哪个服务器,会话的接收数据缓冲,会话的名字、
然后建立一个LoginRoom的实例,并将本聊天加入到LoginRoom中去。
LoginRoom类继承自Room超类,所以其中包含了一个ChatSession的列表,用于管理包含在本room中的会话。每次有新用户进入,则将其放入sessions列表中;当有用户退出时。则将该ChatSession类移出列表。
当用户login时,程序将调用do_login方法。然后将向ChatSession类传入使用中的ChatRoom实例(该实例在ChatServer类初始化时实例化),ChatSession调用自身的enter方法,将自身的room变量从LoginRoom更新为ChatRoom,同时调用LoginRoom的remove方法,将自己从LoginRoom的用户列表中移出。再调用ChatRoom的add方法,将自身添加到ChatRoom的用户列表中。
当用户logout时,与之类似,程序将调用do_logout方法,然后向ChatSession中传入LogoutRoom实例(调用的同时实例化),ChatSession用自身的enter方法,将其从ChatRoom中退出,然后加入到LogoutRoom中去,然后调用默认的中断连接方法,终止连接。
注意,当用户接入时,不管进入那个room,命令调用过程都是一样的:
在collect_incoming_data方法中尝试调用超类CommandHandler的handle方法,handle方法将命令自动拼接,然后调用对应room中的do_xx方法。如果调用handle时返回的是EndSession异常,那么调用handle_close()方法,终止连接。
此外,调试中发现一个意外:
当LogoutRoom类中的add方法下self.server.users不幸写错为self.server.use时,asyncore会在某不知名时刻报错。似乎在asyncore某些位置会调用这个方法。然后报错的出错点在ChatSession类下的cur.remove()处,说list中无该实例。原因不明。
思考:
当用户从LoginRoom进入ChatRoom中时,原先的LoginRoom实例是否会被回收?
用户logout之后,对应的ChatSession实例是否会被回收?感觉这个是asyncore保证的,但是在pycharm中是否可以进行观察跟踪?
0 0
- Python基础教程之虚拟茶话会程序分析
- [Python-*-读书]Python基础教程--虚拟茶话会
- Python基础教程项目(5)虚拟茶话会
- python 基础教程 24章 虚拟茶话会 async1
- python 基础教程 24章 虚拟茶话会 async2
- python 基础教程 24章 虚拟茶话会 async3
- python 基础教程 24章 虚拟茶话会 async4
- python 基础教程 24章 虚拟茶话会 async5
- Python项目五: 虚拟茶话会
- python项目练习五:虚拟茶话会
- python项目练习五:虚拟茶话会
- python项目练习五:虚拟茶话会
- 《python数据分析基础教程》
- 茶话会
- python 基础教程之文件
- Python基础教程之字符串
- python程序之profile分析
- python 基础教程之字符串字典
- spring mvc ContentNegotiatingViewResolver 根据路径后缀,选择不同视图
- C++引用作为返回值
- NagiosQL添加监控主机及Nagios上启用报警机制
- 70MainActivity注册监听联系人变化
- linux 模块交叉编译
- Python基础教程之虚拟茶话会程序分析
- HDOJ 2049 不容易系列之(4)——考新郎
- C++用const 保护 引用参数的传递
- php遍历windows下中文目录下的所有文件名
- mysql用法精华集锦
- IE下Select下拉框宽度无法自适应Bug
- select into from 与 insert into select 区别鉴赏
- mysql日期类型学习
- 网络技术相关