python實現的websocket總結 —— wspy


之前曾有php版的websocket封裝包。見Websocket——php實戰,近期使用python做一些功能,須要用到對websocket的操作,因此,參照之前的實現,實現了這個python版本號。

源代碼見https://github.com/OshynSong/wspy


總體實現起來,須要在建立socket監聽port。這須要用到socket標准庫模塊。之后。須要對對網絡字節流進行操作,這個方面python有struct標准庫模塊。這個很好用;另外涉及到加密解密操作,還有hashlib模塊和sha模塊等使用。特別在此總結一下。目的主要是
1 備忘
2. 總結與思考

1 socket 操作

1 本地Socket建立

建立TCPserver的一般流程:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((addr,port))
sock.listen(10)

建立好本地socket,並綁定地址與port進行監聽。

2 並發連接策略

之后,須要使用不同的策略處理多個client連接的問題,最普通的處理方式就是直接使用accept堵塞,這樣server端每次僅僅能處理一個client連接。然后python標准庫提供了select模塊,里面有select、poll和epoll這些不同的並發連接的處理策略。當中poll和epoll僅僅能在linux下使用,並且epoll在linux 2.6之后的版本號才干使用。當然並發處理效果來看。epoll比poll性能更好。poll比select性能更優。

可是select確能夠在多種平台下使用,為了兼容Windows系統。本次實現中使用的是select策略,詳細例如以下:

... #接上述socket建立代碼
while True:
    rs, ws, es = select.select([sock], [], [])
    for r in rs:
        if r is sock: #r 是server端socket
            cliSock,addr = r.accept()
            r.connect(cliSock) #建立於client連接
        else:
            try:
                data = r.recv(bufferLen)
                ... #處理client連接發送的數據
     ...

poll方法也是select模塊內的方法。使用起來比select更簡單。首先使用poll建立一個poll對象,然后使用它的register方法注冊一個文件描寫敘述符,unregister方法能夠移除注冊對象。之后能夠調用poll方法得到(fd,event)格式的列表,fd是文件描寫敘述符。event代表發生的事件。

event是一個位掩碼。能夠使用select模塊的常量進行按位操作。
select模塊中polling事件常量:

事件名 描寫敘述
POLLIN 讀取來自文件描寫敘述符的數據
POLLPRI 讀取來自文件描寫敘述符的緊急數據
POLLOUT 文件描寫敘述符的數據已准備好。可無堵塞寫入
POLLERR 與文件描寫敘述符有關的錯誤情況
POLLHUP 掛起,連接丟失
POLLNVAL 無效請求,連接沒有打開

以下是使用poll策略的演示樣例代碼:

... #接上述socket建立代碼
fdmap = {sock.fileno() : s}
p = select.poll()
p.register(sock)
while True:
    events = p.poll()
    for fd,event in events:
        if fd in fdmap:  #本地socket
            c,addr = sock.accept()
            print 'Connected from ', addr
            p.register(c)
            fdmap[c.fileno()] = c
        elif event & select.POLLIN:
            data = fdmap[fd].recv(buffer)
            ...#數據操作
        elif event & select.POLLERR: #斷開連接
            p.unregister(fd)
            del fdmap[fd]
   ......

2 Struct處理字節數據

這個標准庫模塊就是用來轉換python的數據值與C風格的數據類型的交互,特別是二進制文件和網絡的字節數據。基本的方法:

struct.pack(fmt, v1, v2…)
struct.pack_into(fmt, buffer, offset, v1, v2…) (將v1,v2等值依照fmt格式pack到buffer字符串以offset開始的之后的位置)
struct.unpack(fmt, string)
struct.unpack_from(fmt, buffer [, offset=0])
struct.calcsize(fmt) (計算fmt的長度)

上面主要是直接使用struct模塊的方法,每一個fmt都須要單獨進行。假設須要重用。能夠使用struct提供的Struct類。使用fmt實例化Struct對象之后,調用相似方法就能夠進行重用。並且這樣使用對象調用的性能更好,比直接使用上述方法調用效率更高。

pack(v1,v2…)
pack_into(buffer, offset, v1, v2 …)
unpack(string)
unpack_from(buffer, offset=0)
format : 返回實例化Struct對象使用的fmt字符串
size:返回fmt字符串的長度

當中最關鍵的format字符串的使用。
首先是字節順序:

Character Byte order Size Alignment
@ native native native
= native standard none
< little-endian standard none
> big-endian standard none
! network (= big-endian) standard none

然后就是format使用特殊字符,見下表:

Format C Type Python type Standard size
x pad byte no value
c char string of length 1 1
b signed char integer 1
B unsigned char integer 1
? _Bool bool 1
h short integer 2
H unsigned short integer 2
i int integer 4
I unsigned int integer 4
l long integer 4
L unsigned long integer 4
q long long integer 8
Q unsigned long long integer 8
f float float 4
d double float 8
s char[] string
p char[] string
P void * integer

3 加密解密處理

hashlib標准庫模塊提供了經常使用的全部加密解密hash方法。使用到的有:

hashlib.update(arg):將hash對象使用arg字符串更新。多次調用相當於將全部arg字符串連接到一起
hashlib.digest() : 返回傳如到update方法的字符串的hash值
hashlib.hexdigest():返回hash值的十六進制字符串表示
hashlib.copy():返回一個hash值的副本

websocket中在握手階段須要獲取到client的key,然后使用sha1和base64進行加密處理后發送到client進行握手。

    sha1Encrypt = sha1(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest()
    acceptKey = base64.b64encode(sha1Encrypt)

總體來說,使用python實現這些操作很方便。與php相比更加簡潔。彰顯了python語言簡潔的本質!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM