Python练习2-基本聊天程序-虚拟茶会话

网友投稿 634 2022-11-16

Python练习2-基本聊天程序-虚拟茶会话

Python练习2-基本聊天程序-虚拟茶会话

基本聊天程序

先来个基本的测试例子:

Main.py

from asyncore import dispatcherimport socket,asyncorePORT = 11223class ChatServer(dispatcher): def __init__(self, port): dispatcher.__init__(self) self.create_socket(socket.AF_INET ,socket.SOCK_STREAM) self.set_reuse_addr() self.bind(('',port)) self.listen(5) def handle_accept(self): conn,addr = self.accept() print ('Connection attempt from',addr[0]) if __name__ == '__main__': s = ChatServer(PORT) try:asyncore.loop()except KeyboardInterrupt:pass

上面是服务器段程序,接受到连接之后马上在服务器上显示对方IP,但是不保持连接。客户端测试的话很简单,可以自己写一个socket的连接,也可以为了省事直接本地开启telnet就行了,开启telnet的方法是,在开始菜单里搜索:

然后确定,之后cmd里直接telnet就行了。

运行上面的main.py,然后客户端链接服务端:

Cmd->telnet    : open 127.0.0.1 11223

Python服务器脚本流程。接下来实现一个基本的聊天程序用来练手。

实现的基本功能(虚拟茶会话) 测试环境python 3.6.0[python基础教程上的代码不能直接在3.6.0版本上跑,以下是改过的虚拟茶会话]

功能:

login name 登录房间

logout 退出房间

say   XXXX 发言

look 查看同一个房间内的人

who 查看谁登陆了当前服务器

测试截图

简单说下设计结构:

CommandHandler类 : 处理命令的,函数存在则执行,不存在则直接走unknown函数。结合着try和getattr函数python可以直接尝试去执行一个不确定存不存在的函数。[我一直在想,别的语言要怎么实现这个东西,是创建虚拟工厂?对了想起来了,干脆就创建一些函数,然后把函数名字格式化封装在一个void指针容器里的了。函数格式化要统一]

Room类:表示一个房间,里面有一些对房间人[链接]数据结构的增加删除操作,同时还有相关广播函数,用于把消息发给所有人。

LoginRoom类,里面有成功登陆房间,登陆房间失败以及登陆操作,比如问候登陆者,同时通知别人有人登陆等细节。

LogoutRoom类,登出房间类,用户登出房间时候进行的一些数据结构处理。

ChatRoom类,聊天室类,主要就是封装了一些功能函数。比如say look who等等。

ChatSession,ChatServer 类基本的服务器程序需要的,分别继承async_chat和dispatcher,处理一些服务器参数,以及重载设置一些处理函数等。

详细代码如下[注意本代码测试于python3.6.0]

#!/usr/bin/env python3__author__ = 'tcstory'from asyncore import dispatcherfrom asynchat import async_chatimport socket, asyncore PORT=5005NAME='TestChat' class EndSession(Exception): pass class CommandHandler: ''' Simple command handler similar to cmd.Cmd from the standard library ''' def unknown(self, session, cmd): 'Respond to an unknown command' session.push('Unkonw command: {0}\r\n'.format(cmd).encode()) def handle(self, session, line): 'Handle a received line from a given session' if not line.strip(): return #Split off the command parts = line.split(' ', 1) cmd = parts[0] try: line=parts[1].strip() except IndexError: line='' #Try to find a handler meth=getattr(self,'do_'+cmd,None) try: #Assume it's callable meth(session,line) except TypeError: #If it isn't ,respond to the unknown command self.unknown(session,cmd) class Room(CommandHandler): ''' A generic environment that may contain one or more users(sessions).it takes care of basic command handling and broadcasting. ''' def __init__(self,server): self.server=server self.sessions=[] def add(self,session): 'A session(user) has entered the room' self.sessions.append(session) def remove(self,session): 'A session (user) has left the room' self.sessions.remove(session) def broadcast(self,line): 'Send a line to all sessions in the room' for session in self.sessions: session.push(line.encode()) def do_logout(self,session,line): 'Respond to the logout command' raise EndSession class LoginRoom(Room): ''' A room meant for a single person who has just connected ''' def add(self,session): Room.add(self,session) #When a user enters,greet him/her self.broadcast('Welcome to {0}\r\n'.format(self.server.name)) def unknown(self, session, cmd): #All unknown commands (anything except login or logout) #results in a prodding session.push('Please log in\nUse "login "\r\n'.encode()) def do_login(self,session,line): name=line.strip() #Make sure the user has entered a name if not name: session.push('Please enter a name\r\n'.encode()) #Make sure that the name isn't in use elif name in self.server.users: session.push('The name {0} is taken.\r\n'.format(name).encode()) session.push('Please try again.\r\n'.encode()) else: #The name is OK,os it is stored in the session.and #the user is moved into the main room session.name=name session.enter(self.server.main_room) class ChatRoom(Room): ''' A room meant for multiple users who can chat with the others in the room ''' def add(self,session): #Notify everyone that a new user has entered self.broadcast('{0} has entered the room.\r\n'.format(session.name)) self.server.users[session.name]=session Room.add(self,session) def remove(self,session): Room.remove(self,session) #Notify everyone that a user has left self.broadcast('{0} has left the room.\r\n'.format(session.name)) def do_say(self,session,line): self.broadcast(('{0}: '+line+'\r\n').format(session.name)) def do_look(self,session,line): 'Handles the look command,used to see who is in a room' session.push('The following are in this room:\r\n'.encode()) for other in self.sessions: session.push('{0}\r\n'.format(other.name).encode()) def do_who(self,session,line): 'Handles the who command ,used to see who is logged in' session.push('The following are logged in:\r\n'.encode()) for name in self.server.users: session.push('{0}\r\n'.format(name).encode()) class LogoutRoom(Room): ''' A simple room for a single user.Its sole purpose is to remove the user's name from the server ''' def add(self,session): #When a session (user) enters the LogoutRoom it is deleted try: del self.server.users[session.name] except KeyError: pass class ChatSession(async_chat): ''' A single session,which takes care of the communication with a single user ''' def __init__(self,server,sock): # async_chat.__init__(self,sock) super().__init__(sock) self.server=server self.set_terminator(b'\r\n') self.data=[] self.name=None #All sessions begin in a separate LoginRoom self.enter(LoginRoom(server)) def enter(self,room): # Remove self from current room and add self to next 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) except EndSession: self.handle_close() def handle_close(self): async_chat.handle_close(self) self.enter(LogoutRoom(self.server)) class ChatServer(dispatcher): ''' A chat server with a single room ''' def __init__(self,port,name): super().__init__() # 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()

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Qtech 暑假未讲到的算法(不完全)
下一篇:hdoj 3732 Ahui Writes Word (多重背包)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~