从Beginning Python: From Novice to Professional, Second Edition 中的一个chatroom项目中拿出来的。那里的聊天室,只有一个单间聊天室功能,使用asyncore和asynchat实现,只能群聊。后来我给它加上了多人聊天室功能。还加上了私聊等功能。改用twisted实现并把它变成了守护模式(使用twistd)
命令列表:
/login username [roomname]
/who 查看当前登录的用户
/look 查看在当前聊天房间的用户
/to username content 私信用户
/exit 退出当前聊天房间
/logout 退出聊天服务器
代码如下:
from twisted.internet import reactor
from twisted.internet.protocol import Protocol,Factory
from twisted.internet import defer
from twisted.protocols.basic import LineReceiver
from twisted.application import internet,service
from twisted.python import log
class commaneHandler:
def handle(self,session,line):
if not line.strip():return
parts=line.split(' ',1)
cmd=parts[0].strip()
try:
if cmd[0]!='/':
cmd="/say"
line=line.strip()
else:
line=parts[1].strip()
except IndexError:
line=""
finally:
cmd=cmd[1:].strip()
meth=getattr(self,"do_"+cmd,None)
try:
meth(session,line)
except TypeError:
self.unknow(session,cmd)
def unknow(self,session,cmd):
session.write("%s:unknow command!\n"%cmd)
class Room(commaneHandler):
def __init__(self,server,name=""):
self.server=server
self.roomName=name
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.write(line+'\n')
def do_list(self,session,line):
session.write("list for ChatRoom\n")
for room in self.server.rooms:
session.write(room+'\n')
def do_logout(self,session,line):
session.entry(LogoutRoom(self.server))
session.d.errback("")
class LoginRoom(Room):
def add(self,session):
Room.add(self,session)
log.msg("Connection from %s "%session.session.getPeer())
session.write("Welcome to ChatTest for twisted v1.1!\n")
def do_login(self,session,line):
parts=line.strip().split(" ")
name=parts[0]
if not name:
session.write("Please entry a name\n")
elif name in self.server.users:
session.write("The name %s is token\n"%name)
else:
session.name=name
try:
roomName=parts[1]
except IndexError:
roomName="main"
if not roomName in self.server.rooms:
self.server.createRoom(roomName)
session.entry(self.server.rooms[roomName])
def unknow(self,session,line):
session.write("Commands:login logout list\n")
class LogoutRoom(Room):
def add(self,session):
try:
del self.server.users[session.name]
except KeyError:
pass
class ChatRoom(Room):
def add(self,session):
session.write("Welcome to ChatRoom:%s !\n"%self.roomName)
mess=session.name+" has join the room"
self.broadcast(mess)
log.msg(mess)
Room.add(self,session)
self.server.users[session.name]=session
def remove(self,session):
Room.remove(self,session)
self.broadcast(session.name+" has left the room")
def do_say(self,session,line):
self.broadcast("%s: %s"%(session.name,line))
def do_look(self,session,line):
session.write("list for room:\n")
for i,other in enumerate(self.sessions):
session.write("%d: %s\n"%(i,other.name))
def do_exit(self,session,line):
try:
del self.server.users[session.name]
except KeyError:
pass
session.entry(LoginRoom(self.server))
def do_to(self,session,line):
try:
parts=line.split(' ',1)
name=parts[0]
line=parts[1]
toUser=self.server.users[name]
toUser.write("%s: %s\n"%(session.name,line))
except IndexError:
session.write("Usage:/to toUser line\n")
return False
except KeyError:
session.write("%s does not exist!\n"%name)
return False
def do_who(self,session,line):
session.write("list for server:\n")
for i,name in enumerate(self.server.users.keys()):
session.write("%d: %s\n"%(i,name))
class chatSession:
def __init__(self,server,session,d):
self.d=d
self.server=server
self.session=session
self.name=None
self.entry(LoginRoom(self.server,""))
def write(self,line):
self.session.write(line)
def entry(self,room):
try:
cur=self.room
except AttributeError:
pass
else:
cur.remove(self)
self.room=room
room.add(self)
def execComm(self,line):
self.room.handle(self,line.strip())
class ChatProtocol(LineReceiver):
def connectionMade(self):
d=defer.Deferred()
d.addBoth(self.endSession)
self.s=chatSession(self.factory,self.transport,d)
def endSession(self,_):
self.transport.loseConnection()
def connectionLost(self,reason):
pass
def connectionFailure(self,connector,reason):
print reason
def lineReceived(self,line):
self.s.execComm(line)
class ChatFactory(Factory):
protocol=ChatProtocol
def __init__(self):
self.users={}
self.rooms={}
self.createRoom("main")
def createRoom(self,name):
self.rooms[name]=ChatRoom(self,name)
port=1234
iface="localhost"
application=service.Application("chatRoom")
top_service=service.MultiService()
factory=ChatFactory()
tcp_service=internet.TCPServer(port,factory,
interface=iface)
tcp_service.setServiceParent(top_service)
top_service.setServiceParent(application)
输出:
ljd&11:44:51:py$ twistd -n -y tw_chatRoom.py
2014-06-21 11:45:01+0800 [-] Log opened.
2014-06-21 11:45:01+0800 [-] twistd 11.1.0 (/usr/bin/python 2.7.3) starting up.
2014-06-21 11:45:01+0800 [-] reactor class: twisted.internet.pollreactor.PollReactor.
2014-06-21 11:45:01+0800 [-] ChatFactory starting on 1234
2014-06-21 11:45:01+0800 [-] Starting factory <__builtin__.ChatFactory instance at 0xfe6368>
2014-06-21 11:45:09+0800 [__builtin__.ChatFactory] Connection from IPv4Address(TCP, '127.0.0.1', 58755)
2014-06-21 11:45:23+0800 [ChatProtocol,0,127.0.0.1] abc has join the room