python3实现聊天室

一直没有写过python异步方面的代码,最近看到ascyncore这个库,就参照python基础教程写了一个类似qq的聊天室。记录下一些坑。 


 废话不多说,先看一个最简单的聊天室的架构图。



1. socket相关的api 参数在python3.2以上都改为了 byte类型

2. super().method() === Fu.method(self)


from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore 

class EndSession(Exception): pass


class ChatServer(dispatcher):
    def __init__(self, port, name):
        super().__init__()
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.bind(('', port))
        self.listen(10)
        self.name = name 
        self.users = {}     # 管理用户信息
        self.main_room = ChatRoom(self)

    def handle_accepted(self, conn, addr):
        ChatSession(self, conn) 


class ChatSession(async_chat):
    """维持每一个客户端对接"""
    def __init__(self, server, sock):
        super().__init__(sock)
        self.server = server 
        self.set_terminator(b"\r\n")        # 注意这个地方要是byte(debug了好久,,不看文档的结果。。)
        self.data = []
        self.name = None
        self.enter(LoginRoom(server))       # 所有的客户端 一连接 就进入LoginRoom (可以当成一个单人的聊天室)
    
    def enter(self, room):
        try:
            cur = self.room
            cur.remove(self)
        except AttributeError: pass
        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:      # 自定义的一个 exception 
            self.handle_close() 

    def handle_close(self):
        async_chat.handle_close(self) # TODO:等同于super().handle_close()
        self.enter(LogoutRoom(self.server))

    def push(self, message):
        """一个小坑,push中的message必须encode一下成byte,str类型不能直接传给push"""
        super().push(message.encode("utf-8"))



class Room:
    """聊天室"""
    def __init__(self, server):
        self.server = server 
        self.sessions = []

    def unknown(self, session, cmd):
        """处理没有规定的 命令"""
        session.push("Unknown command: {}s\r\n".format(cmd))        # push用来做服务器的回应

    def handle(self, session, cmd):
        if not cmd.strip(): return 
        parts = cmd.split(" ",1)
        cmd = parts[0]
        try: 
            line = parts[1].strip()
        except IndexError:
            line = ""
        try:
            meth = getattr(self, "do_" + cmd, None)
            meth(session, line)
        except TypeError:
            self.unknown(session, cmd)

    def add(self, session):
        self.sessions.append(session)
    
    def remove(self, session):
        self.sessions.remove(session)
    
    def broadcast(self, message):
        for session in self.sessions:
            session.push(message)


class LoginRoom(Room):
    def add(self, session):
        super().add(session)
        self.broadcast("Welcome to {}\r\n".format(self.server.name))        #.encode("utf-8"))

    def do_login(self, session, line):
        name = line.strip()
        if not name:
            session.push("Please enter a name\r\n")
        elif name in self.server.users:
            session.push("The name is exist!\r\n")
            session.push("please try again\r\n")
        else:
            session.name = name
            session.enter(self.server.main_room)


class ChatRoom(Room):
    def add(self, session):
        self.sessions.append(session)
        self.server.users[session.name] = session
        self.broadcast(session.name + " has entered the room.\r\n")

    def remove(self, session):
        self.broadcast(session.name + " has leave the room.\r\n")
        super().remove(session)

    def do_say(self, session, message):
        self.broadcast(session.name + ": {}\r\n".format(message))

    def do_look(self, session, message):
        session.push(str([session.name for session in self.sessions])+ "\r\n")

    def do_who(self, session, message):
        session.push("The following are logged in :\r\n")
        for name in self.server.users:
            session.push(name+"\r\n")


class LogoutRoom(Room):
    def add(self, session):
        try:
            del self.server.users[session.name]
        except KeyError: 
            pass

if __name__ == "__main__":
    s = ChatServer(5050,"test")
    try: 
        asyncore.loop()
    except KeyboardInterrupt:
        print()复制代码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值