简单聊天室<一>

背景

互联网上在线聊天服务的种类很多, 如IRC, 在Python中实现这样一个方法, 可以使用Twisted框架.

自己写一个的原因:

学习网络编程基本的知识 看书笔记总结

聊天服务器基本的功能如下:

服务器能接受不同客户端的连接允许用户并行操作能够解释命令, 如在shell中的操作

初次实现1 迷你服务器

from asyncore import dispatcherimport asyncoreclass ChatServer(dispatcher):    passs = ChatServer()asyncore.loop

2 可以接受连接的服务器

from asyncore import dispatcherimport asyncoreimport socketPORT = 5267class ChatServer(dispatcher):    def handle_accept(self):        conn, addr = self.accept()        print 'Connection from ', addr[0]s = ChatServer()s.create_socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('', PORT))s.listen(5)asyncore.loop()

handle_accept方法会调用允许客户端连接的self.accept函数. 他返回一个连接和一个地址, 初始化的过程, 调用了create_socket创建套接字, bind来绑定端口, listen用来监听. 试着运行下面的语句:

telnet localhost 5267

会出现如下

fish@love67:~$telnet localhost 5267Connection form 127.0.0.1

3 具有一些清理功能的服务器

上面的程序使用键盘关闭(ctrl + c等)会导致堆栈跟踪, 为了避免这类情况, 可以在 try/except 语句放置loop. 再加上一点清理功能, 如下:

from asyncore import dispatcherimport asyncoreimport socketPORT = 5267class ChatServer(dispatcher):    def __init__(self, port):        # 子类的初始化, 也可以用super        dispatcher.__init__(self, port)        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)        # 清理函数 set_reuse_addr()        self.set_reuse_addr()        self.bind(('', port))        self.listen(5)    def handle_accept(self):        conn, addr = self.accept()        print 'Connection from ' , addr[0]if __name__ == '__main__':        s = ChatServer(PORT)        try:            asyncore.loop()        except KeyboardInterrupt:            pass

4 ChatSession类

下面代码中, async_chat类(位于asynchat中)的好处是他隐藏了大多数基本的套接字读写操作, 为了让他起作用, 只需要覆盖两个函数: collect_incoming_datafound_terminator. 前者每次从套接字中读取一些bit文本时调用, 后者在读取一个结束符是调用.

from asyncore import dispatcherfrom asynchat import async_chatimport asyncore, socketPORT = 5267class ChatSession(async_chat):    def __init__(self, sock):        asyncore.__init__(self, sock)        self.set_terminator('\r\n')        self.data = []    # 函数覆盖    def collect_incoming_data(self, data):        self.data.append(data)    # 函数覆盖      def found_terminator(self):        line = ''.join(self.data)        self.data = []        print lineclass ChatServer(dispatcher):    def __init__(self, port):        dispatcher.__init__(self, port)        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)        self.set_reuse_addr()        self.bind(('', port))        self.listen(5)        self.sessions = []    def handle_accept(self):        conn, addr = self.accept()        self.sessions.append(ChatSession(conn))if __name__ == '__main__':    s = ChatServer(PORT)    try:        asyncore.loop()    except KeyboardInterrupt:        pass

值得注意的是:

code>set_terminator</code>方法用于终止对象, 设定为网络卸协议中经常使用的终止符\r\nChatSession 对象会将目前读取的数据保存为字符串列表data, 当读取更多数据时, collect_incoming_data会自动调用, 将读取的数据追加到列表中found_terminator方法在读取到终止符时停止, 并将self.data重置为空列表.ChatServer保存会话列表


整合简单的聊天服务器

from asyncore import dispatcherimport asyncore, socketfrom asynchat import async_chatPORT = 5267NAME = "ChatRoom"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.push('Welcome to %s \r\n', %self.server)    def collect_incoming_data(self, data):        self.data.append(data)     def found_terminator(self):        "如果发现了一个终止符, 说明读入了完整的一行, 将其广播给所有人"        line = ''.join(self.data)        self.data = []        self.server.broadcast(line)    def handle_close(self):        async_chat.handle_close(self)        self.server.disconnect(self)class ChatServer(dispatcher):    "接收连接并产生单个会话的类,  他还会处理到其他会话的广播"    def __init__(self, port, name):        dispatcher.__init__(self, port)        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)        self.set_reuse_addr()        self.bind(('', port))        self.name = name        self.listen(5)        self.sessions = []    def disconnect(self, session):        self.sessions.remove(session)    def broadcast(self, session):        for session in self.sessions:            session.push(line + '\r\n')    def handle_accept(self):        conn, addr = self.accept()        self.sessions.append(ChatSession(self, conn))if __name__ == '__main__':    s = ChatServer(PORT, NAME)    try:        asyncore.loop()    except KeyboardInterrupt:        pass
简单聊天室<一>

相关文章:

你感兴趣的文章:

标签云: