亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

通過(guò)Swoole Framework學(xué)習(xí)websocket協(xié)議

wenyiweb / 872人閱讀

摘要:服務(wù)端的開(kāi)發(fā)離不開(kāi)協(xié)議,的出現(xiàn)對(duì)于學(xué)習(xí)通信來(lái)說(shuō),無(wú)疑是非常好的教材。一旦握手成功,一個(gè)雙向連接通道就建立了。類型包括文本,二進(jìn)制,協(xié)議層信號(hào)等。目前一共有種類型,種保留類型。表示異或,表示取模。

  

服務(wù)端的開(kāi)發(fā)離不開(kāi)協(xié)議,swoole的出現(xiàn)對(duì)于學(xué)習(xí)通信來(lái)說(shuō),無(wú)疑是非常好的教材。非常推薦大家下載 Swoole Framework,其中包含了多種協(xié)議的php實(shí)現(xiàn),例如FTP,HTTP,Websocket等。本文大部分代碼都是受這個(gè)項(xiàng)目的啟發(fā),當(dāng)然學(xué)習(xí)的同時(shí)別忘了star一下這個(gè)項(xiàng)目。筆者本身計(jì)算機(jī)基礎(chǔ)較弱,寫(xiě)這篇文章的同時(shí)也查了不少資料,如果有錯(cuò)誤歡迎提出批評(píng)。

websocket協(xié)議學(xué)習(xí) 概述

協(xié)議分為兩部分:握手,數(shù)據(jù)傳輸

客戶端發(fā)出的握手信息類似:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

服務(wù)器返回的握手信息類似:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13

兩段信息的第一行大家應(yīng)該都比較熟悉,是HTTP協(xié)議中的Request-Line和Status-Line,RFC2616。下面接著出現(xiàn)的是無(wú)序的頭信息,這和HTTP協(xié)議相同。 一旦握手成功,一個(gè)雙向連接通道就建立了。
連接用于傳輸message, message由一個(gè)或多個(gè)frame組成。每個(gè)frame有一個(gè)類型,屬于同一個(gè)message的frame的類型都相同。類型包括:文本,二進(jìn)制,control frame(協(xié)議層信號(hào))等。目前一共有6種類型,10種保留類型。

握手

根據(jù)上面的客戶端頭信息可以看出,握手和HTTP是兼容的。WS的握手是HTTP的"升級(jí)版本"。

客戶端發(fā)送的握手請(qǐng)求必須
1. 是一個(gè)合法的HTTP請(qǐng)求
2. 方法是GET
3. 頭必須包含HOST字段
4. 頭必須包含Upgrade字段,值為websocket,可以看作是判斷請(qǐng)求為ws的標(biāo)志。
5. 頭必須包含Connection字段,值為Upgrade。
6. 頭必須包含Sec-WebSocket-Key字段,用于驗(yàn)證。
7. 如果請(qǐng)求來(lái)自瀏覽器,頭必須包含 Origin字段。
8. 頭必須包含Sec-WebSocket-Version字段,值為13

驗(yàn)證握手

Sec-WebSocket-Key字段的值,連接一個(gè)GUID字符串,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11", sha1 hash一下,再base64_encode,得到的值作為字段Sec-WebSocket-Accept的值返回給客戶端。用php代碼表示:

"Sec-WebSocket-Accept" => base64_encode(sha1($key . static::GUID, true))

同時(shí),返回的狀態(tài)設(shè)置為101,其他狀態(tài)都表示握手沒(méi)有成功。 Connection,Upgrade字段作為HTTP升級(jí)版必須存在。一個(gè)握手返回如下:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Frame(幀)的結(jié)構(gòu)如下:
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-------+-+-------------+-------------------------------+
 |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
 |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
 |N|V|V|V|       |S|             |   (if payload len==126/127)   |
 | |1|2|3|       |K|             |                               |
 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 |     Extended payload length continued, if payload len == 127  |
 + - - - - - - - - - - - - - - - +-------------------------------+
 |                               |Masking-key, if MASK set to 1  |
 +-------------------------------+-------------------------------+
 | Masking-key (continued)       |          Payload Data         |
 +-------------------------------- - - - - - - - - - - - - - - - +
 :                     Payload Data continued ...                :
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 |                     Payload Data continued ...                |
 +---------------------------------------------------------------+

FIN: 1 bit, 標(biāo)記是否是最后一個(gè)message的最后一個(gè)片段

RSV1, RSV2, RSV3: 各 1 bit, 保留標(biāo)記,都為0

Opcode:4 bits, 是對(duì)payload data的說(shuō)明,指明這個(gè)幀的類型。

0x0 表明為接著上一幀的連續(xù)幀

0x1 表明為text frame

0x2 表明為binary frame

0x3-7 保留

0x8 表示連接關(guān)閉

0x9 為ping

0xA 為pong

0xB-F 保留

- Mask: 1 bit, 指明Payload data是否被mask,如果為1,那么數(shù)據(jù)需要根據(jù)masking-key來(lái)unmask??蛻舳税l(fā)送的幀都是mask的。
- Payload length: 7 bits 或 7+16 bits 或 7+64 bits. 如果值為0-125,那么該值就是payload的長(zhǎng)度;如果為126,那么接下來(lái)的2個(gè)byte表示payload長(zhǎng)度(16bit, unsigned); 如果為127,那么接下來(lái)的8個(gè)bytes表示payload的長(zhǎng)度(64bit, unsigned)。
- Masking-key: 0 或 4 bytes, 用于unmask payload data。
- Payload data: 長(zhǎng)度為 Payload length, 可以分為 extension data + application data, 擴(kuò)展數(shù)據(jù)的長(zhǎng)度計(jì)算方法是是事先商議好的,剩余的就是應(yīng)用數(shù)據(jù)。

Mask規(guī)則

masking-key是客戶端隨意指定的32bit長(zhǎng)度值。從原始數(shù)據(jù)到masked數(shù)據(jù)的方式為:原始數(shù)據(jù)第i個(gè)字節(jié)的值 XOR masking-key的第(i%4)個(gè)字節(jié)的值。XOR表示異或,%表示取模。

片段化的作用

當(dāng)傳遞一個(gè)未知長(zhǎng)度的數(shù)據(jù)時(shí),可以不用一下子buffer全部的數(shù)據(jù)。尤其當(dāng)數(shù)據(jù)非常大時(shí),可以分多次buffer,包裝為frame來(lái)發(fā)送。

嘗試解析一個(gè)frame

看到這里,我們已經(jīng)了解了frame的結(jié)構(gòu),是否想嘗試解析一個(gè)frame,官方文檔提供了幾段二進(jìn)制數(shù)據(jù),我們可以用來(lái)練習(xí)一下。我挑選了其中兩段, 代碼如下:

php> 7) & 0x1;
    $RSV1 = ($temp >> 6) & 0x1;
    $RSV2 = ($temp >> 5) & 0x1;
    $RSV3 = ($temp >> 4) & 0x1;
    $opcode = $temp & 0xf;

    echo "First byte: FIN is $FIN, RSV1-3 are $RSV1, $RSV2, $RSV3; Opcode is $opcode 
";

    $temp = ord($data[$offset++]);
    $mask = ($temp >> 7) & 0x1;
    $payload_length = $temp & 0x7f;
    if($payload_length == 126){
        $temp = substr($data, $offset, 2);
        $offset += 2;
        $temp = unpack("nl", $temp);
        $payload_length = $temp["l"];
    }elseif($payload_length == 127){
        $temp = substr($data, $offset, 8);
        $offset += 8;
        $temp = unpack("nl", $temp);
        $payload_length = $temp["l"];
    }
    echo "mask is $mask, payload_length is $payload_length 
";

    if($mask ==0){
        $temp = substr($data, $offset);
        $content = "";
        for ($i=0; $i < $payload_length; $i++) { 
            $content .= $temp[$i];
        }
    }else{
        $masking_key = substr($data, $offset, 4);
        $offset += 4;

        $temp = substr($data, $offset);
        $content = "";
        for ($i=0; $i < $payload_length; $i++) { 
            $content .= chr(ord($temp[$i]) ^ ord($masking_key[$i%4]));
        }
    }

    echo "content is $content 
";
}

結(jié)果輸出如下圖:

  

到這里其實(shí)并不算完,ws協(xié)議還有很多很多規(guī)則,RFC文檔實(shí)在是太長(zhǎng)了。比如,如何應(yīng)對(duì)每一種control frame,有詳細(xì)的說(shuō)明;如何關(guān)閉連接;協(xié)議擴(kuò)展;錯(cuò)誤處理;安全相關(guān);一些基本的內(nèi)容都能在swoole framework中找到對(duì)應(yīng)的代碼。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/21069.html

相關(guān)文章

  • swoolefy-基于swoole擴(kuò)展實(shí)現(xiàn)的高性能的常駐內(nèi)存型API和Web應(yīng)用服務(wù)框架

    摘要:是一個(gè)基于擴(kuò)展實(shí)現(xiàn)的輕量級(jí)高性能的常駐內(nèi)存型的和應(yīng)用服務(wù)框架高度封裝了,,服務(wù)器,以及基于實(shí)現(xiàn)可擴(kuò)展的服務(wù),同時(shí)支持包方式安裝部署項(xiàng)目?;趯?shí)用,抽象事件處理類,實(shí)現(xiàn)與底層的回調(diào)的解耦,支持同步異步調(diào)用,內(nèi)置等常用組件等。 swoolefy swoolefy是一個(gè)基于swoole擴(kuò)展實(shí)現(xiàn)的輕量級(jí)高性能的常駐內(nèi)存型的API和Web應(yīng)用服務(wù)框架,高度封裝了http,websocket,ud...

    lewinlee 評(píng)論0 收藏0
  • php只能做網(wǎng)站?基于swoole+websocket開(kāi)發(fā)雙向通信應(yīng)用

    摘要:那么,是否就無(wú)法用來(lái)開(kāi)發(fā)雙向通信的應(yīng)用呢答案是否定的。內(nèi)置通信支持,可以與程序基于進(jìn)行雙向通信。通信協(xié)議于年被定為標(biāo)準(zhǔn),并由補(bǔ)充規(guī)范。前言 眾所周知,PHP用于開(kāi)發(fā)基于HTTP協(xié)議的網(wǎng)站應(yīng)用非常便捷。而HTTP協(xié)議是一種單向的通信協(xié)議,只能接收客戶端的請(qǐng)求,然后響應(yīng)請(qǐng)求,不能主動(dòng)向客戶端推送信息。因此,一些實(shí)時(shí)性要求比較高的應(yīng)用,如實(shí)時(shí)聊天、直播應(yīng)用、在線網(wǎng)頁(yè)游戲等,就不適合采用HTTP協(xié)議...

    番茄西紅柿 評(píng)論0 收藏0
  • php只能做網(wǎng)站?基于swoole+websocket開(kāi)發(fā)雙向通信應(yīng)用

    摘要:那么,是否就無(wú)法用來(lái)開(kāi)發(fā)雙向通信的應(yīng)用呢答案是否定的。內(nèi)置通信支持,可以與程序基于進(jìn)行雙向通信。通信協(xié)議于年被定為標(biāo)準(zhǔn),并由補(bǔ)充規(guī)范。前言 眾所周知,PHP用于開(kāi)發(fā)基于HTTP協(xié)議的網(wǎng)站應(yīng)用非常便捷。而HTTP協(xié)議是一種單向的通信協(xié)議,只能接收客戶端的請(qǐng)求,然后響應(yīng)請(qǐng)求,不能主動(dòng)向客戶端推送信息。因此,一些實(shí)時(shí)性要求比較高的應(yīng)用,如實(shí)時(shí)聊天、直播應(yīng)用、在線網(wǎng)頁(yè)游戲等,就不適合采用HTTP協(xié)議...

    ?。琛?/span> 評(píng)論0 收藏0
  • swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? docker 了解

    摘要:源碼解讀系列一好難都跑不起來(lái)怎么破了解一下唄閱讀框架源碼第一步搞定環(huán)境小伙伴剛接觸的時(shí)候會(huì)感覺(jué)壓力有點(diǎn)大更直觀的說(shuō)法是難開(kāi)發(fā)組是不贊成難這個(gè)說(shuō)法的的代碼都是實(shí)現(xiàn)的而又是世界上最好的語(yǔ)言的代碼閱讀起來(lái)是很輕松的開(kāi)發(fā)組會(huì)用源碼解讀系列博客深 date: 2018-8-01 14:22:17title: swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? doc...

    shenhualong 評(píng)論0 收藏0
  • swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? docker 了解

    摘要:源碼解讀系列一好難都跑不起來(lái)怎么破了解一下唄閱讀框架源碼第一步搞定環(huán)境小伙伴剛接觸的時(shí)候會(huì)感覺(jué)壓力有點(diǎn)大更直觀的說(shuō)法是難開(kāi)發(fā)組是不贊成難這個(gè)說(shuō)法的的代碼都是實(shí)現(xiàn)的而又是世界上最好的語(yǔ)言的代碼閱讀起來(lái)是很輕松的開(kāi)發(fā)組會(huì)用源碼解讀系列博客深 date: 2018-8-01 14:22:17title: swoft| 源碼解讀系列一: 好難! swoft demo 都跑不起來(lái)怎么破? doc...

    rollback 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<