## Websocket協議
> Websocket是html5提出的一個協議規范,參考rfc6455。
>
> websocket約定了一個通信的規范,通過一個握手的機制,客戶端(瀏覽器)和服務器(webserver)之間能建立一個類似tcp的連接,從而方便c-s之間的通信。在websocket出現之前,web交互一般是基于http協議的短連接或者長連接。
>
> WebSocket是為解決客戶端與服務端實時通信而產生的技術。websocket協議本質上是一個基于tcp的協議,是先通過HTTP/HTTPS協議發起一條特殊的http請求進行握手后創建一個用于交換數據的TCP連接,此后服務端與客戶端通過此TCP連接進行實時通信。
### Websocket和HTTP協議的關系
同樣作為應用層的協議,WebSocket在現代的軟件開發中被越來越多的實踐,和HTTP有很多相似的地方,這里將它們簡單的做一個純個人、非權威的比較:
#### 相同點
1. 都是基于TCP的應用層協議。
2. 都使用Request/Response模型進行連接的建立。
3. 在連接的建立過程中對錯誤的處理方式相同,在這個階段WS可能返回和HTTP相同的返回碼。
4. 都可以在網絡中傳輸數據。
#### 不同點
1. WS使用HTTP來建立連接,但是定義了一系列新的header域,這些域在HTTP中并不會使用。
2. WS的連接不能通過中間人來轉發,它必須是一個直接連接。
3. WS連接建立之后,通信雙方都可以在任何時刻向另一方發送數據。
4. WS連接建立之后,數據的傳輸使用幀來傳遞,不再需要Request消息。
5. WS的數據幀有序。
### 協議
#### 1. 握手
客戶端發起握手。
```http
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
```
從上面的協議中可以看到websocket基于HTTP協議的GET。而且只支持GET.
**Upgrade**:upgrade是HTTP1.1中用于定義轉換協議的header域。它表示,如果服務器支持的話,客戶端希望使用現有的「網絡層」已經建立好的這個「連接(此處是TCP連接)」,切換到另外一個「應用層」(此處是WebSocket)協議。
**Connection**:HTTP1.1中規定Upgrade只能應用在「直接連接」中,所以帶有Upgrade頭的HTTP1.1消息必須含有Connection頭,因為Connection頭的意義就是,任何接收到此消息的人(往往是代理服務器)都要在轉發此消息之前處理掉Connection中指定的域(不轉發Upgrade域)。
**Sec-WebSocket-***:第7行標識了客戶端支持的子協議的列表(關于子協議會在下面介紹),第8行標識了客戶端支持的WS協議的版本列表,第5行用來發送給服務器使用(服務器會使用此字段組裝成另一個key值放在握手返回信息里發送客戶端)。
服務端響應
```http
HTTP/1.1 101 Switching Protocols
Content-Length: 0
Upgrade: websocket
Sec-Websocket-Accept: ZEs+c+VBk8Aj01+wJGN7Y15796g=
Server: TornadoServer/4.5.1
Connection: Upgrade
Date: Wed, 21 Jun 2017 03:29:14 GMT
```
Sec-Websocket-Accept 是一個校驗。用客戶端發來的sec_key 服務器通過sha1計算拼接商GUID【258EAFA5-E914-47DA-95CA-C5AB0DC85B11 】 。然后再base64encode
#### 數據傳輸
客戶端和服務器連接成功后,就可以進行通信了,通信協議格式是WebSocket格式,服務器端采用Tcp Socket方式接收數據,進行解析,協議格式如下:

這里使用的是數據存儲的位(bit),當進行加密的時候,最終要的一位就是最左邊的第一個。
- FIN :1bit ,表示是消息的最后一幀,如果消息只有一幀那么第一幀也就是最后一幀。
- RSV1,RSV2,RSV3:每個1bit,必須是0,除非擴展定義為非零。如果接受到的是非零值但是擴展沒有定義,則需要關閉連接。
- Opcode:4bit,解釋Payload數據,規定有以下不同的狀態,如果是未知的,接收方必須馬上關閉連接。狀態如下:0x0(附加數據幀) 0x1(文本數據幀) 0x2(二進制數據幀) 0x3-7(保留為之后非控制幀使用) 0xB-F(保留為后面的控制幀使用) 0x8(關閉連接幀) 0x9(ping) 0xA(pong)
-
Mask:1bit,掩碼,定義payload數據是否進行了掩碼處理,如果是1表示進行了掩碼處理。
```
Masking-key域的數據即是掩碼密鑰,用于解碼PayloadData。客戶端發出的數據幀需要進行掩碼處理,所以此位是1。
```
- Payload length:7位,7 + 16位,7+64位,payload數據的長度,如果是0-125,就是真實的payload長度,如果是126,那么接著后面的2個字節對應的16位無符號整數就是payload數據長度;如果是127,那么接著后面的8個字節對應的64位無符號整數就是payload數據的長度。
- Masking-key:0到4字節,如果MASK位設為1則有4個字節的掩碼解密密鑰,否則就沒有。
- Payload data:任意長度數據。包含有擴展定義數據和應用數據,如果沒有定義擴展則沒有此項,僅含有應用數據。
### 客戶端
```js
var websocket = new WebSocket("ws://127.0.0.1")
websocket.onopen = function(){
}
websocket.onmessage = function(){}
websocket.onclose = function(){}
```
- PC
- IO模型
- Inode介紹
- Linux
- Linux基本操作命令
- Linux網絡相關命令
- Crontab計劃任務
- Shell
- Sed命令
- Awk命令
- LAMP/LNMP
- PHP
- 基本語法
- 面向對象
- 錯誤和異常處理
- 命名空間
- PHP7
- 正則表達式
- Hashtable
- 變量的內部實現
- PHP-FPM
- PHP運行原理
- swoole
- mysql
- SQL標準
- mysql三范式
- 存儲引擎
- Mysql事務
- Mysql索引
- Mysql優化
- Explain
- MySQL索引原理及慢查詢優化
- MongoDb
- 計算機網絡
- IP協議
- TCP(傳輸控制協議)
- UDP(用戶數據報協議)
- HTTP 協議
- HTTPS
- HTTP的基本優化
- Websocket協議
- 版本控制器
- Git
- Svn
- 數據結構
- 數組
- 鏈表
- 算法