IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    简单聊天室<二>

    Fish (fsh267@gmail.com)发表于 2014-02-18 00:00:00
    love 0

    #功能添加

    上文算是个功能完善的聊天服务器, 但是拓展功能有限. 而且不能解释命令, 因此需要增加对与身份和命令解释的支持, 而且还要确保按照每个会话的状态采取适当的行为.

    ###基础命令解释

    比如, 输入say, hello world , 程序应当执行do_say("hello world").

    class CommandHandler:
        def unkown(self, session, cmd):
            session.push("unkown commad %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.unkown(session, cmd)


    ###添加房间

    class EndSession(Exception): pass
    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 EndSession

    #最后版本

    主聊天室也要覆盖add和remove方法, 此外, ChatRoom 还会实现如下3条命令:

    • say: 广播一个单行
    • look: 告诉房间有哪些用户

    ##简单聊天室

    # coding: utf-8
    from asyncore import dispatcher
    from asynchat import async_chat
    import socket, asyncore
    
    PORT = 5267
    NAME = 'FISH'
    USAGE = '''
    	login name --登陆服务器
    	logout     --登出
    	say words  --发言
    	look       --查看房间内的用户
    	who        --查看登陆服务器的人
    	========================================
    	'''
    # 结束会话
    class EndSession(Exception):
    	pass
    
    class CommandHandler:
    	'''
    		类似cmd中命令处理简单程序
    	'''
    	def unknown(self,session, cmd):
    		# 响应未知命令
    		session.push('Unknown command %s \r\n' % cmd)
    		session.push('Check the usage : \r\n %s' %USAGE)
    	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):
    		# 响应logout命令
    		raise EndSession
    class LoginRoom(Room):
    	'''
    		为连接到的用户做准备工作
    	'''
    	def add(self, session):
    		Room.add(self, session)
    		# 向客户端问候一下
    		self.broadcast('Welcome to %s\r\n' %self.server.name)
    		self.broadcast('Chcek the usage : \r\n %s' %USAGE)
    	def unknown(self, session, cmd):
    		# 未知命令的处理, 弹出一个警告
    		session.push('Please log in\n use "login <nick> " \r\n')
    	def do_login(self, session, line):
    		name = line.strip()
    		# 确定输入了nickname
    		if not name:
    			session.push('Please enter a name \r\n')
    		elif name in self.server.users:
    			session.push('Sorry, the name %s in in use' %name)
    			session.push('\n Please input another one:\r\n')
    		else:
    			# 名字okay, 就保存到users中
    			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 followings are in the room : \r\n')
    		for user in self.sessions:
    			session.push(user.name + '\r\n')
    		session.push('=' * 20 + '\r\n')
    	def do_who(self, session, line):
    		session.push('The followings are logged in:\r\n')
    		for name in self.server.users:
    			session.push(name + '\r\n')
    		session.push('=' * 20 + '\r\n')
    
    class LogoutRoom(Room):
    	# 为单用户准备的简单房间,只用于将用户名重服务器移除
    	def add(self, session):
    		# 当会话进入要删除的lougoutroom
    		try:
    			del self.server.users[session.name]
    		except KeyError:
    			pass
    class 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
    		# 所有的会话开始于单独的LoginRoom中
    		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	

    #ScreenShot:


    Git源代码



沪ICP备19023445号-2号
友情链接