最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

這次的問題首先有一個前提,就是得用Python來實(shí)現(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ù)實(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實(shí)現(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é)果的原因,是因?yàn)閮蓚€版本的協(xié)議的Data Framing結(jié)構(gòu)不同,也即是在握手建立連接后,Client發(fā)送和接收的數(shù)據(jù)結(jié)構(gòu)都不一樣。

首先第一步需要獲取不同版本協(xié)議下Client發(fā)送過來的原始數(shù)據(jù)。老版本協(xié)議比較簡單,實(shí)際上就是在原始數(shù)據(jù)前加了個'\x00′,在最后面加上了一個'\xFF',所以如果Safari的Client發(fā)送一個字符串'test',實(shí)際上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í)際數(shù)據(jù)的長度;如果這個數(shù)值剛好等于0111 1110 (126),那么接下來的2個字節(jié)才代表真實(shí)數(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ù),就是實(shí)際的data…的兄弟了。說是兄弟,是因?yàn)檫@個數(shù)據(jù)是實(shí)際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)文章

  • django使用圖片延時加載引起后臺404錯誤

    django使用圖片延時加載引起后臺404錯誤

    本文給大家介紹的是作者在Django中使用圖片的延時加載技術(shù)后引起后臺404錯誤的問題以及解決思路和方法,有需要的小伙伴可以參考下
    2017-04-04
  • Python刪除空文件和空文件夾的方法

    Python刪除空文件和空文件夾的方法

    這篇文章主要介紹了Python刪除空文件和空文件夾的方法,涉及Python針對文件與文件夾的遍歷、判斷與刪除等技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • Python正則表達(dá)式和元字符詳解

    Python正則表達(dá)式和元字符詳解

    這篇文章主要介紹了Python正則表達(dá)式和元字符詳解,需要的朋友可以參考下
    2018-11-11
  • python二維碼操作:對QRCode和MyQR入門詳解

    python二維碼操作:對QRCode和MyQR入門詳解

    今天小編就為大家分享一篇python二維碼操作:對QRCode和MyQR入門詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • python實(shí)現(xiàn)數(shù)據(jù)寫入excel表格

    python實(shí)現(xiàn)數(shù)據(jù)寫入excel表格

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)數(shù)據(jù)寫入excel表格,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 十行Python代碼實(shí)現(xiàn)文字識別功能

    十行Python代碼實(shí)現(xiàn)文字識別功能

    這篇文章主要和大家分享如何調(diào)用百度的接口實(shí)現(xiàn)圖片的文字識別。整體是用Python實(shí)現(xiàn),所需要使用的第三方庫包括aip、PIL、keyboard、pyinstaller,需要的可以參考一下
    2022-05-05
  • PyTorch訓(xùn)練LSTM時loss.backward()報錯的解決方案

    PyTorch訓(xùn)練LSTM時loss.backward()報錯的解決方案

    這篇文章主要介紹了PyTorch訓(xùn)練LSTM時loss.backward()報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • OpenCV 模板匹配

    OpenCV 模板匹配

    這篇文章主要介紹了OpenCV 模板匹配功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • python中wordcloud安裝的方法小結(jié)

    python中wordcloud安裝的方法小結(jié)

    這篇文章主要介紹了安裝python中wordcloud的幾種方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • 編寫Python腳本使得web頁面上的代碼高亮顯示

    編寫Python腳本使得web頁面上的代碼高亮顯示

    這篇文章主要介紹了編寫Python腳本使得web頁面上的代碼高亮顯示,主要使用了pygments工具,需要的朋友可以參考下
    2015-04-04

最新評論

乌恰县| 绵竹市| 西城区| 永吉县| 墨竹工卡县| 昌宁县| 兴安县| 红原县| 凯里市| 河池市| 普宁市| 云和县| 宝鸡市| 东安县| 宝坻区| 承德市| 竹山县| 蒙阴县| 吐鲁番市| 汕尾市| 扎鲁特旗| 和硕县| 肃宁县| 晋宁县| 桂平市| 涟源市| 临海市| 荆州市| 邵阳市| 边坝县| 和田市| 启东市| 宁安市| 沿河| 尖扎县| 桂阳县| 庐江县| 嵊州市| 襄垣县| 哈密市| 工布江达县|