1. 程式人生 > >Python實現web聊天室

Python實現web聊天室

支持 put all rem message one utf cti 訪問

使用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)


Python實現web聊天室