简单聊天室<二>
#功能添加
上文算是个功能完善的聊天服务器, 但是拓展功能有限. 而且不能解释命令, 因此需要增加对与身份和命令解释的支持, 而且还要确保按照每个会话的状态采取适当的行为.
###基础命令解释
比如, 输入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:
blog comments powered by Disqus
Published
18 February 2014