欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python實現(xiàn)同時兼容老版和新版Socket協(xié)議的一個簡單WebSocket服務(wù)器

 更新時間:2014年06月04日 09:53:23   作者:  
這篇文章主要介紹了Python實現(xiàn)同時兼容老版和新版Socket協(xié)議的一個簡單WebSocket服務(wù)器,需要的朋友可以參考下

最近在做的一個項目中需要使用到HTML5中引入的WebSocket技術(shù),本來以為應(yīng)該很容易就能搞定,誰知道在真正上手開發(fā)了以后才發(fā)現(xiàn)有很多麻煩的地方,雖然我們是一個以前端開發(fā)和設(shè)計見長的團(tuán)隊,而且作為一個二手程序猿又長期不被待見,但是為了讓有同樣需求的朋友少走些彎路,我還是決定把實現(xiàn)方法貼在這個地方。

關(guān)于WebSocket的基本概念,維基百科上解釋的很清楚,而且網(wǎng)上也能搜出來一大把,這里就略過不表,直接進(jìn)入正題。

這次的問題首先有一個前提,就是得用Python來實現(xiàn)這個服務(wù)器,如果對具體語言沒有限制的話,推薦大家首選Node.js的一個第三方庫:Socket.IO,非常好用,10分鐘不打針不吃藥搞定WebSocket Server,而且用JS來寫后端,相信也能對上很多文藝開發(fā)者的胃口。

但是如果選擇用Python,google搜索的結(jié)果幾乎都不能用,最要命的問題是,WebSocket協(xié)議本身還是一個草案,所以不同瀏覽器支持的協(xié)議版本有所不同,Safari 5.1支持的是老版本協(xié)議Hybi-02,Chrome 15以及Firefox 8.0支持的是新版本協(xié)議Hybi-10,老版本協(xié)議和新版本協(xié)議在建立通信的握手方法還有數(shù)據(jù)傳輸?shù)母袷揭笊隙加兴煌?,?dǎo)致網(wǎng)上大多數(shù)實現(xiàn)方式只能適用于Safari瀏覽器,并且Safari和C&F瀏覽器之間無法互相通信。

首先第一步需要解釋的是新、舊版本W(wǎng)ebSocket協(xié)議的握手方式。我們先來看看三個不同瀏覽器發(fā)送的握手?jǐn)?shù)據(jù)的結(jié)構(gòu):

Chrome:

復(fù)制代碼 代碼如下:

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: 127.0.0.1:1337
Sec-WebSocket-Origin: http://127.0.0.1:8000
Sec-WebSocket-Key: erWJbDVAlYnHvHNulgrW8Q==
Sec-WebSocket-Version: 8
Cookie: csrftoken=xxxxxx; sessionid=xxxxx

Firefox:
復(fù)制代碼 代碼如下:
GET / HTTP/1.1
Host: 127.0.0.1:1337
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:8.0) Gecko/20100101 Firefox/8.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive, Upgrade
Sec-WebSocket-Version: 8
Sec-WebSocket-Origin: http://127.0.0.1:8000
Sec-WebSocket-Key: 1t3F81iAxNIZE2TxqWv+8A==
Cookie: xxx
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

Safari:
復(fù)制代碼 代碼如下:
GET / HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: 127.0.0.1:1337
Origin: http://127.0.0.1:8000
Cookie: sessionid=xxxx; calView=day; dayCurrentDate=1314288000000
Sec-WebSocket-Key1: cV`p1* 42#7  ^9}_ 647  08{
Sec-WebSocket-Key2: O8 415 8x37R A8   4
;"######

 

可以看出,Chrome和Firefox實現(xiàn)的是新版協(xié)議,因此只傳輸了一個”Sec-WebSocket-Key”頭以供服務(wù)端生成握手Token,但是遵循老版本的Safari的數(shù)據(jù)中有兩個Key:”Sec-WebSocket-Key1″和”Sec-WebSocket-Key2″,因此服務(wù)端在生成握手Token的時候,需要做一次判斷。先來看使用老版本協(xié)議的Safari,Token生成算法如下:

取出Sec-WebSocket-Key1中的所有數(shù)字字符形成一個數(shù)值,這里是1427964708,然后除以Key1中的空格數(shù)目,這里好像是6個空格,得到一個數(shù)值,保留該數(shù)值整數(shù)位,得到數(shù)值N1;對Sec-WebSocket-Key2如法炮制,得到第二個整數(shù)N2;把N1和N2按照Big-Endian字符序列連接起來,然后再與另外一個Key3連接,得到一個原始序列ser_key。那么Key3是什么呢?大家可以看到在Safari發(fā)送過來的握手請求最后,有一個8字節(jié)的奇怪的字符串“;”######”,這個就是Key3?;氐絪er_key,對這個原始序列做md5算出一個16字節(jié)長的digest,這就是老版本協(xié)議需要的token,然后將這個token附在握手消息的最后發(fā)送回Client,即可完成握手。

新版協(xié)議生成Token的方法比較簡單:首先把Sec-WebSocket-Key和一串固定的UUID “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”做拼接,然后對這個拼接后的字符串做SHA1加密,得到digest以后,做一次base64編碼,即可獲得Token。

另外需要注意的是,新版本和老版本握手協(xié)議回傳給Client的數(shù)據(jù)結(jié)構(gòu)有所不同,在附件中的server源碼中寫得很清楚了,看看就能明白。
完成握手只是WebSocket Server的一半功能,現(xiàn)在只能保證這個Server能夠和兩個版本的瀏覽器建立鏈接了,但是如果試著把Chrome中的消息發(fā)送給Safari,會發(fā)現(xiàn)Safari無法接收。導(dǎo)致這個結(jié)果的原因,是因為兩個版本的協(xié)議的Data Framing結(jié)構(gòu)不同,也即是在握手建立連接后,Client發(fā)送和接收的數(shù)據(jù)結(jié)構(gòu)都不一樣。

首先第一步需要獲取不同版本協(xié)議下Client發(fā)送過來的原始數(shù)據(jù)。老版本協(xié)議比較簡單,實際上就是在原始數(shù)據(jù)前加了個'\x00′,在最后面加上了一個'\xFF',所以如果Safari的Client發(fā)送一個字符串'test',實際上WebSocket Server收到的數(shù)據(jù)是:'x00test\xFF',所以只需要剝離掉首尾那兩個字符就可以了。

比較麻煩的是新版本協(xié)議的數(shù)據(jù),按照新版draft的解釋,Chrome和Firefox發(fā)過來的數(shù)據(jù)報文由以下幾個部分組成:首先是一個固定的字節(jié)(1000 0001或是1000 0002),這個字節(jié)可以不用理會。麻煩的是第二個字節(jié),這里假設(shè)第二個字節(jié)是1011 1100,首先這個字節(jié)的第一位肯定是1,表示這是一個”masked”位,剩下的7個0/1位能夠計算出一個數(shù)值,比如這里剩下的是 011 1100,計算出來就是60,這個值需要做如下判斷:

如果這個值介于0000 0000 和 0111 1101 (0 ~ 125) 之間,那么這個值就代表了實際數(shù)據(jù)的長度;如果這個數(shù)值剛好等于0111 1110 (126),那么接下來的2個字節(jié)才代表真實數(shù)據(jù)長度;如果這個數(shù)值剛好等于0111 1111 (127),那么接下來的8個字節(jié)代表數(shù)據(jù)長度。

有了這個判斷之后,能夠知道代表數(shù)據(jù)長度的字節(jié)在第幾位結(jié)束,比如我們舉得例子60,這個值介于0~125之間,所以第二個字節(jié)本身就代表了原始數(shù)據(jù)的長度了(60個字節(jié)),所以從第三個字節(jié)開始,我們能抓出4個字節(jié)來,這一串字節(jié)叫做 “masks” (掩碼?),掩碼之后的數(shù)據(jù),就是實際的data…的兄弟了。說是兄弟,是因為這個數(shù)據(jù)是實際data根據(jù)掩碼做過一次位運(yùn)算后得到的,獲得原始data的方法是,將兄弟數(shù)據(jù)的每一位x,和掩碼的第i%4位做xor運(yùn)算,其中i是x在兄弟數(shù)據(jù)中的索引。看得眼花是吧,看看下面這個代碼片段也許就能明白了:

復(fù)制代碼 代碼如下:

def send_data(raw_str):
    back_str = []

    back_str.append('\x81')
    data_length = len(raw_str)

    if data_length < 125:
        back_str.append(chr(data_length))
    else:
        back_str.append(chr(126))
        back_str.append(chr(data_length >> 8))
        back_str.append(chr(data_length & 0xFF))

    back_str = "".join(back_str) + raw_str

這樣生成的back_str,就能夠發(fā)送給使用新版協(xié)議的Chrome或是Firefox了。

至此,這個簡單的WebSocket Server就完成了,能夠同時兼容老版協(xié)議和新版協(xié)議的Socket連接,以及不同版本之間的數(shù)據(jù)傳輸。該Server的源碼請點(diǎn)擊這里下載,需要注意的是里面用到了twisted框架來跑TCP服務(wù),代碼寫得不怎么樣,僅供大家參考。

相關(guān)文章

  • python的正則表達(dá)式re模塊的常用方法

    python的正則表達(dá)式re模塊的常用方法

    Python 的 re 模塊(Regular Expression 正則表達(dá)式)提供各種正則表達(dá)式的匹配操作,在文本解析、復(fù)雜字符串分析和信息提取時是一個非常有用的工具,下面我主要總結(jié)了re的常用方法
    2013-03-03
  • 在Python中用keys()方法返回字典鍵的教程

    在Python中用keys()方法返回字典鍵的教程

    這篇文章主要介紹了在Python中用keys()方法返回字典鍵的教程,是Python入門中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05
  • Python爬取京東商品信息評論存并進(jìn)MySQL

    Python爬取京東商品信息評論存并進(jìn)MySQL

    這篇文章主要介紹了Python爬取京東商品信息評論存并進(jìn)MySQL,文章通過構(gòu)建mysql數(shù)據(jù)表展開Python爬取信息存進(jìn)MySQL的內(nèi)容,需要的小伙伴可以參考一下
    2022-04-04
  • Django Model層F,Q對象和聚合函數(shù)原理解析

    Django Model層F,Q對象和聚合函數(shù)原理解析

    這篇文章主要介紹了Django Model層F,Q對象和聚合函數(shù)原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • 七個生態(tài)系統(tǒng)核心庫[python自學(xué)收藏]

    七個生態(tài)系統(tǒng)核心庫[python自學(xué)收藏]

    無論你是想快速入手Python,還是想成為數(shù)據(jù)分析大神或者機(jī)器學(xué)習(xí)大佬,亦或者對Python代碼進(jìn)行優(yōu)化,本文的python庫都能為你提供一些幫助
    2021-08-08
  • python文件和目錄操作函數(shù)小結(jié)

    python文件和目錄操作函數(shù)小結(jié)

    這篇文章主要介紹了python文件和目錄操作函數(shù)小結(jié),主要涉及到os模塊和shutil模塊的一些方法,需要的朋友可以參考下
    2014-07-07
  • django的登錄注冊系統(tǒng)的示例代碼

    django的登錄注冊系統(tǒng)的示例代碼

    這篇文章主要介紹了django的登錄注冊系統(tǒng)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Python解析微信dat文件的方法

    Python解析微信dat文件的方法

    這篇文章主要介紹了Python解析微信dat文件的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Python中參數(shù)打包和解包的實現(xiàn)

    Python中參數(shù)打包和解包的實現(xiàn)

    在Python中,打包和解包參數(shù)是一種操作方式,可以將多個參數(shù)打包成一個元組或字典,也可以將一個元組或字典解包成多個參數(shù),本文就來介紹一下如何使用
    2023-09-09
  • python集合類型用法分析

    python集合類型用法分析

    這篇文章主要介紹了python集合類型用法,實例分析了Python中集合的功能及常見使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04

最新評論