2022年2022年关于python基础教程项目聊天服务器的实现 .pdf
本人是个python 初学者, 选择的入门书籍是python 基础教程第二版,因为看网上说这本书最后有十个项目非常好,所以就选择了这本书。但是没想到其中的项目5:虚拟茶话会可是让我郁闷了好久,因为照着打出来的代码居然有那么多奇怪的错误(其实代码本身没什么错误,应该还是自己打错了)。上网去查,看到有不少人都遇到了这个问题,但是我没找到一个解决的。所以我就写下了这篇经验贴,希望可以帮助和我遇到一样问题的朋友。不多说,直接上代码:# -coding: utf-8 - from asyncore import dispatcher from asynchat import async_chat import socket, asyncore PORT = 5000 NAME = Sasu&Saly class EndSession(Exception): pass class CommandHandler: 类似于标准库中的cmd。Cmd 的简单命令处理程序。 def unknown(self, session, cmd): 相应未知命令 session.push(Unknown command: %srn % cmd) def handle(self, session, line): 处理从给定会话中接收到的行 if not line.strip(): return 分离命令 parts = line.split( , 1) cmd = parts0 try: line = parts1.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 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 5 页 - - - - - - - - - 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): 响应 logout 命令 raise EndSession class LoginRoom(Room): 为刚刚连接上的用户准备的房间 def add(self, session): 当用户进入时,发出问候 Room.add(self, session) self.broadcast(Welcome to %srn % self.server.name) def unknown(self, session, line): 所有未知命令会导致一个警告 session.push(Please log innUse loginrn) def do_login(self, session, line): name = line.strip() if not name: session.push(Please enter a namern) elif name in self.server.users: session.push(The name %s is taken.rn % name) session.push(Please try again.rn) else: session.name = name session.enter(self.server.main_room) class ChatRoom(Room): 为多用户相互聊天准备的房间 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 5 页 - - - - - - - - - def add(self, session): 告诉所有人有新用户进入 self.broadcast(session.name + has entered the room.rn) self.server.userssession.name = session Room.add(self, session) def remove(self, session): Room.remove(self, session) 告诉所有人有用户离开 self.broadcast(session.name + has left the room.rn) def do_say(self, session, line): self.broadcast(session.name+:+line+rn) def do_look(self, session, line): 处理 look 命令,该命令用于查看谁在房间内 session.push(The following are in this room: rn) for other in self.sessions: session.push(other.name + rn) def do_who(self, session, line): 处理 who 命令,该命令用于查看谁登录了 session.push(The following are logged in:rn) for name in self.server.users: session.push(name + rn) class LogoutRoom(Room): 为单用户准备的房间。只用于将用户名从服务器移除 def remove(self, session): try: del self.server.userssession.name except KeyError: pass class ChatSession(async_chat): 单会话,负责和单用户通信 def _init_(self, server, sock): async_chat._init_(self, sock) self.server = server self.set_terminator(rn) self.data = self.name = None self.enter(LoginRoom(server) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 5 页 - - - - - - - - - def enter(self, room): 从当前房间移出自身(self) ,并且将自身添加到下一个房间 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 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 5 页 - - - - - - - - - 这次代码我依然是照着书写的,不过不同的是我是边学一个类边写一个类,并且写一点就测试一点, 所以最后写完时错误就很少了。但是! ! ! 还是有错误, 还是那种很奇怪的错误。当时指示的是CommandHandler 的 handle 函数有错,但还没说哪行错了,我就一直看一直看,最后觉得 parts = line.split( ,1)这句不对劲, 不知道 split 的参数对不对, 就去查了手册,最后发现它的第一个参数其实是一个空格!我当时中间没有空格!这个函数的功能是分割字符串, 也就是我们程序中的命令,那个空格代表按空格分隔!把这块改过来后,程序就能正确运行了。还有一个问题,要注意python 的版本!我最一开始是用python3 做的,有错误。 python3 和 2 好像有较多的改动,这个程序最好在python2 运行。其实作者的代码是没有错的,我写这个贴的目的是因为我发现网上有很多人都遇到了这样的问题,而且还都没有解决,所以想给大家一个解决方案。同时我还想给大家(初学者)几点建议:1、 在写这种常代码的时候最好写一点就测试一点,如果都写完再测试,那么错误就太多了,不知道从哪改起了。2、 其实好多时候我们遇到的问题都没有解决的办法,还得靠自己。就这个抄错的程序我整整看了两周,我都觉得自己傻。不过就这么一直不停的找错误,我对这个程序有了比较深刻的理解,还是有很大帮助的。3、 有问题找手册。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 5 页 - - - - - - - - -