Python实现web聊天室

发布时间:2019-09-11 07:44:35编辑:auto阅读(1421)

    使用Python模块中的select模块实现web聊天室功能

    select模块

    Python中的select模块专注于I/O多路复用,提供了select  poll  epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统)


    参数: 可接受四个参数(前三个必须)

        rlist: wait until ready for reading

        wlist: wait until ready for writing

        xlist: wait for an “exceptional condition”

        timeout: 超时时间


    select方法:

        每次调用slect都要将所有的fd拷贝到内核空间(每次都要拷贝),导致效率下降

        每次调用slect都要将所有的fd拷贝到内核空间(每次都要拷贝),导致效率下降

        监听的的实现是通过遍历所有的fd,(遍历消耗的时间消耗多)判断是否有数据访问

        最大连接数(input中放的文件描述符数量1024)

    pull方法:

        最大连接数没有限制了,除此之外和select一样。使用较少

    epull方法:

        内部通过3个函数实现(select是其中一个)

        第一个函数:
          创建epoll句柄,把所有的fd拷贝到内核空间,只需要拷贝一次

        第二个函数: 回调函数
        某一个函数或者动作成功完成后,会自动触发一个函数为所有的fd绑定一个回调函数,一旦有数据访问,触发改回调函数,回调函数把fd放到链表中。(只要有活动,把fd放到链表中,动态监听)这样就提高了效率。例子:交试卷

        第三个函数,判断链表是否为空


    server端代码

    #/usr/bin/env python
    #-*- coding:utf-8 -*-
    import socket
    import select
    # 封装
    class SelectServer(object):
        # 定义主函数
        def __init__(self, host, port, backlog):
            self.host = host
            self.port = port
            self.address = (host, port)
            self.backlog = backlog
            self.server = None
            self.socketList = list()
    
        def _initSocket(self):
            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server.bind(self.address)
            self.server.listen(self.backlog)
            self.socketList.append(self.server)
            print("chat room has start!")
            while 1:
                rlist, wlist, elist = select.select(self.socketList, [], [])
                for r in rlist:
                    if r == self.server:
                        serverConn, clienAddr = self.server.accept()
                        self.socketList.append(serverConn)
                        print("{0}进入了房间".format(clienAddr))
                        self.broadcast(r, "{0}进入了房间".format(clienAddr))
                    else:
                        try:
                            data = r.recv(2048)
                            if data:
                                print("{0}: {1}".format(clienAddr, data))
                                self.broadcast(r, "{0}: {1}".format(clienAddr, data))
                        except Exception as e:
                            self.broadcast(r, "{0}下线".format(clienAddr))
                            print("{0}下线".format(clienAddr))
                            r.close()
                            self.socketList.remove(r)
            self.server.close()
        # 定义广播函数
        def broadcast(self, r, data):
            for i in self.socketList:
                if i != r and i != self.server:
                    try:
                        i.sendall(data)
                    except:
                        i.close()
                        self.socketList.remove(i)
    # 定义main函数
    def main():
        selectServer = SelectServer(host="192.168.154.131", port=9999, backlog=5)
        selectServer._initSocket()
    
    if __name__ == '__main__':
        main()


    client端代码

    #/usr/bin/env python
    #-*- coding:utf-8 -*-
    import socket, select, string, sys
    import time
    
    # main function
    if __name__ == "__main__":
        host = "192.168.154.131"
        port = 9999
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(2)
        try:
            s.connect((host, port))
        except:
            print('Unable to connect')
            sys.exit()
        print('Connected to remote host. Start sending messages')
    
        while 1:
            rlist = [sys.stdin, s]
            read_list, write_list, error_list = select.select(rlist, [], [])
            for sock in read_list:
                if sock == s:
                    data = sock.recv(2048)
                    if not data:
                        continue
                    else:
                        sys.stdout.write(data)
                else:
                    msg = raw_input("我说: ")
                    s.sendall(msg)


关键字