TCP/IP, WebSocket 和 MQTT的瞭解----轉載好文----阿冬專欄!!!

來自:http://www.cnblogs.com/shanyou/p/4085802.html

難得一見的好文,上面鏈接

TCP/IP, WebSocket 和 MQTT

按照OSI網絡分層模型,IP是網絡層協議,TCP是傳輸層協議,而HTTP和MQTT是應用層的協議。在這三者之間, TCP是HTTP和MQTT底層的協議。大家對HTTP很熟悉,這裏簡要介紹下MQTT。MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通訊協議,有可能成爲物聯網的重要組成部分。該協議支持所有平臺,幾乎可以把所有聯網物品和外部連接起來,被用來當做傳感器的通信協議。

  1. HTTP的不足

    HTTP協議經過多年的使用,發現了一些不足,主要是性能方面的,包括:

    HTTP的連接問題,HTTP客戶端和服務器之間的交互是採用請求/應答模式,在客戶端請求時,會建立一個HTTP連接,然後發送請求消息,服務端給出應答消息,然後連接就關閉了。(後來的HTTP1.1支持持久連接)
    因爲TCP連接的建立過程是有開銷的,如果使用了SSL/TLS開銷就更大。

    在瀏覽器裏,一個網頁包含許多資源,包括HTML,CSS,JavaScript,圖片等等,這樣在加載一個網頁時要同時打開連接到同一服務器的多個連接。

    HTTP消息頭問題,現在的客戶端會發送大量的HTTP消息頭,由於一個網頁可能需要50-100個請求,就會有相當大的消息頭的數據量。

    HTTP通信方式問題,HTTP的請求/應答方式的會話都是客戶端發起的,缺乏服務器通知客戶端的機制,在需要通知的場景,如聊天室,遊戲,客戶端應用需要不斷地輪詢服務器。

    而 WebSocket是從不同的角度來解決這些不足中的一部分。還有其他技術也在針對這些不足提出改進。

  2. WebSocket
    WebSocket則提供使用一個TCP連接進行雙向通訊的機制,包括網絡協議和API,以取代網頁和服務器採用HTTP輪詢進行雙向通訊的機制。

    本質上來說,WebSocket是不限於HTTP協議的,但是由於現存大量的HTTP基礎設施,代理,過濾,身份認證等等,WebSocket借用HTTP和HTTPS的端口。由於使用HTTP的端口,因此TCP連接建立後的握手消息是基於HTTP的,由服務器判斷這是一個HTTP協議,還是WebSocket協議。 WebSocket連接除了建立和關閉時的握手,數據傳輸和HTTP沒丁點關係了。

歷時11年,WebSocket終於被批准成爲IETF的建議標準:RFC6455.其前身是WHATWG Web Hypertext Application Technology Working Group)的工作。而Web SocketAPI,W3C的工作。

WebSocket可以只打開一個到服務器的鏈接,並且在此鏈接上交換信息。其優勢在於減少了傳統方法的複雜性,提高了可靠性和降低了瀏覽器和客戶端之間的負載。這樣做的一個重要原因是,很多防火牆屏蔽80以外的端口,迫使越來越多的應用遷移到HTTP上來了。

11年的websocket草案的變遷中,有的瀏覽器支持的是舊版本的websocket,比如iPhone4上的safari使用的WebSocket是舊版的握手協議,那麼就要使用就的握手協議來製做服務器端。如今只有Safari支持舊版本的協議,ChromeFirefox最新版都已升級至Hybi-10協議地址)。因此,我們再來看一下WebSocket新版協議Hybi-10。這次協議變更非常大,主要集中在握手協議和數據傳輸的格式上。

握手協議

我們先來看一下大致的區別:

  1. 最老的websocket草案標準中是沒有安全key,草案7.57.6中有兩個安全key,而現在的草案10中只有一個安全key,即將 7.57.6http頭中的"Sec-WebSocket-Key1″"Sec-WebSocket-Key2″合併爲了一個"Sec- WebSocket-Key"
  2. http頭中Upgrade的值由"WebSocket"修改爲了"websocket"http頭中的"-Origin"修改爲了"Sec-WebSocket-Origin";
  3. 增加了http"Sec-WebSocket-Accept",用來返回原來草案7.57.6服務器返回給客戶端的握手驗證,原來是以內容的形式返回,現在是放到了http頭中;另外服務器返回客戶端的驗證方式也有變化。

服務器生成驗證的方式變化較大,我們來做一介紹。

舊版:

1 GET / HTTP/1.1
2 Upgrade: WebSocket
3 Connection: Upgrade
4 Host: 127.0.0.1:1337
5 Origin: http://127.0.0.1:8000
6 Cookie: sessionid=xxxx; calView=day; dayCurrentDate=1314288000000
7 Sec-WebSocket-Key1: cV`p1* 42#7  ^9}_ 647  08{
8 Sec-WebSocket-Key2: O8 415 8x37R A8   4
9 ;"######

舊版生成Token的方法如下:

取出Sec-WebSocket-Key1中的所有數字字符形成一個數值,這裏是1427964708,然後除以Key1中的空格數目,得到一個數值,保留該數值整數位,得到數值N1;對Sec-WebSocket-Key2採取同樣的算法,得到第二個整數N2;把N1N2按照Big- Endian字符序列連接起來,然後再與另外一個Key3連接,得到一個原始序列ser_keyKey3是指在握手請求最後,有一個8字節的奇怪的字符";"######",這個就是Key3。然後對ser_key進行一次md5運算得出一個16字節長的digest,這就是老版本協議需要的 token,然後將這個token附在握手消息的最後發送回Client,即可完成握手。

新版:

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

新版生成Token的方法如下:

首先服務器將key(長度24)截取出來,如4tAjitqO9So2Wu8lkrsq3w==,用它和自定義的一個字符串(長度 36258EAFA5-E914-47DA-95CA-C5AB0DC85B11連接起來,然後把這一字符串進行SHA-1算法加密,得到長度爲20節的二進制數據,再將這些數據經過Base64編碼,最終得到服務端的密鑰,也就是ser_key。服務器將ser_key附在返回值Sec- WebSocket-Accept後,至此握手成功。

WebSocket也有自己一套幀協議。數據報文格式如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

      0                   1                   2                   3

      01234567890123456789012345678901

     +-+-+-+-+-------+-+-------------+-------------------------------+

     |F|R|R|R|opcode|M|Payload len|    Extended payload length    |

     |I|S|S|S|  (4)  |A|     (7)     |             (16/63)           |

     |N|V|V|V|       |S|             |   (ifpayload len==126/127)   |

     ||1|2|3|       |K|             |                               |

     +-+-+-+-+-------+-+-------------+---------------+

     |     Extended payload length continued,ifpayload len==127  |

     +---------------+-------------------------------+

     |                               |Masking-key,ifMASK set to1  |

     +-------------------------------+-------------------------------+

     |Masking-key(continued)       |          Payload Data         |

     +-----------------------------------------------+

     :                     Payload Data continued...                :

     +-------------------------------+

     |                     Payload Data continued...                |

     +---------------------------------------------------------------+

FIN1位,用來表明這是一個消息的最後的消息片斷,當然第一個消息片斷也可能是最後的一個消息片斷;

RSV1, RSV2, RSV3: 分別都是1位,如果雙方之間沒有約定自定義協議,那麼這幾位的值都必須爲0,否則必須斷掉WebSocket連接;

Opcode:4位操作碼,定義有效負載數據,如果收到了一個未知的操作碼,連接也必須斷掉,以下是定義的操作碼:

  • %x0 表示連續消息片斷
  • %x1 表示文本消息片斷
  • %x2 表未二進制消息片斷
  • %x3-7 爲將來的非控制消息片斷保留的操作碼
  • %x8 表示連接關閉
  • %x9 表示心跳檢查的ping
  • %xA 表示心跳檢查的pong
  • %xB-F 爲將來的控制消息片斷的保留操作碼

Mask:1位,定義傳輸的數據是否有加掩碼,如果設置爲1,掩碼鍵必須放在masking-key區域,客戶端發送給服務端的所有消息,此位的值都是1

Payload length: 傳輸數據的長度,以字節的形式表示:7位、7+16位、或者7+64位。如果這個值以字節表示是0-125這個範圍,那這個值就表示傳輸數據的長度;如果這個值是126,則隨後的兩個字節表示的是一個16進制無符號數,用來表示傳輸數據的長度;如果這個值是127,則隨後的是8個字節表示的一個64位無符合數,這個數用來表示傳輸數據的長度。多字節長度的數量是以網絡字節的順序表示。負載數據的長度爲擴展數據及應用數據之和,擴展數據的長度可能爲0,因而此時負載數據的長度就爲應用數據的長度。

Masking-key:04個字節,客戶端發送給服務端的數據,都是通過內嵌的一個32位值作爲掩碼的;掩碼鍵只有在掩碼位設置爲1的時候存在。
Payload data:  (x+y)
位,負載數據爲擴展數據及應用數據長度之和。
Extension data:x
位,如果客戶端與服務端之間沒有特殊約定,那麼擴展數據的長度始終爲0,任何的擴展都必須指定擴展數據的長度,或者長度的計算方式,以及在握手時如何確定正確的握手方式。如果存在擴展數據,則擴展數據就會包括在負載數據的長度之內。
Application data:y
位,任意的應用數據,放在擴展數據之後,應用數據的長度=負載數據的長度-擴展數據的長度。

三、 MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是輕量級基於代理的發佈/訂閱的消息傳輸協議,設計思想是開放、簡單、輕量、易於實現。這些特點使它適用於受限環境。例如,但不僅限於此:

  • 網絡代價昂貴,帶寬低、不可靠。
  • 在嵌入設備中運行,處理器和內存資源有限。

該協議的特點有:

  • 使用發佈/訂閱消息模式,提供一對多的消息發佈,解除應用程序耦合。
  • 對負載內容屏蔽的消息傳輸。
  • 使用 TCP/IP 提供網絡連接。
  • 有三種消息發佈服務質量:
  • "至多一次",消息發佈完全依賴底層 TCP/IP 網絡。會發生消息丟失或重複。這一級別可用於如下情況,環境傳感器數據,丟失一次讀記錄無所謂,因爲不久後還會有第二次發送。
  • "至少一次",確保消息到達,但消息重複可能會發生。
  • "只有一次",確保消息到達一次。這一級別可用於如下情況,在計費系統中,消息重複或丟失會導致不正確的結果。
  • 小型傳輸,開銷很小(固定長度的頭部是 2 字節),協議交換最小化,以降低網絡流量。
  • 使用 Last Will 和 Testament 特性通知有關各方客戶端異常中斷的機制。

早在1999年,IBM的Andy Stanford-Clark博士以及Arcom公司ArlenNipper博士發明了MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)技術。BM和St. Jude醫療中心通過MQTT開發了一套Merlin系統,該系統使用了用於家庭保健的傳感器。St. Jude醫療中心設計了一個叫做Merlin@home的心臟裝置,這種無限發射器可以用來監控那些已經植入復律-除顫器和起搏器(兩者都是基本的傳感器)的心臟病人。

該產品利用MQTT把病人的即時更新信息傳給醫生/醫院,然後醫院進行保存。這樣的話,病人就不用親自去醫院檢查心臟儀器了,醫生可以隨時查看病人的數據,給出建議,病人在家裏就可以自行檢查。

IBM稱該發射器包括一個大型觸摸屏,一個嵌入式鍵盤平臺,以及一個Linux操作系統。

在未來幾年,MQTT的應用會越來越廣,值得關注。

通過MQTT協議,目前已經擴展出了數十個MQTT服務器端程序,可以通過PHP,JAVA,Python,C,C#等系統語言來向MQTT發送相關消息。

此外,國內很多企業都廣泛使用MQTT作爲Android手機客戶端與服務器端推送消息的協議。其中Sohu,Cmstop手機客戶端中均有使用到MQTT作爲消息推送消息。據Cmstop主要負責消息推送的高級研發工程師李文凱稱,隨着移動互聯網的發展,MQTT由於開放源代碼,耗電量小等特點,將會在移動消息推送領域會有更多的貢獻,在物聯網領域,傳感器與服務器的通信,信息的收集,MQTT都可以作爲考慮的方案之一。在未來MQTT會進入到我們生活的各各方面。

如果需要下載MQTT服務器端,可以直接去MQTT官方網站點擊software進行下載MQTT協議衍生出來的各個不同版本。

MQTTTCPWebSocket的關係可以用下圖一目瞭然:

MQTT協議專注於網絡、資源受限環境,建立之初不曾考慮WEB環境。HTML5 Websocket是建立在TCP基礎上的雙通道通信,和TCP通信方式很類似,適用於WEB瀏覽器環境。雖然MQTT基因層面選擇了TCP作爲通信通道,但我們添加個編解碼方式,MQTT over Websocket也可以的。這樣做的好處,MQTT的使用範疇被擴展到HTML5、桌面端瀏覽器、移動端WebApp、Hybrid等,多了一些想像空間。這樣看來,無論是移動端,還是WEB端,MQTT都會有自己的使用空間。

一步一步學WebSocket (初識WebSocket

一步一步學WebSocket(使用SuperWebSocket實現自己的服務端

.NET  WebSocket 開發包比較

Websocket全講解。跨平臺的通訊協議!!基於websocket的高併發即時通訊服務器開發。

利用WebSocket傳輸數組或者Blob的方案

MQTT和WebSocket

http://channel9.msdn.com/coding4fun/blog/Machine-2-Machine-with-a-MQTT-Net-Library

MQ 遙測傳輸 (MQTT) V3.1 協議規範基於WebSocket MQTT 移動推送方案

IoT - Messaging with MQTT using Azure and .NET using netduino

MQTT V3.1----flow

MQTT協議簡記

MQTT V3.1--我的理解

MQTT協議筆記之頭部信息

MQTT協議筆記之連接和心跳

MQTT協議筆記之發佈流程

MQTT協議筆記之消息流

MQTT協議筆記之訂閱

MQTT 3.1.1,值得升級的6個新特性

MQTT學習筆記——MQTT協議體驗 Mosquitto安裝和使用                           

The Mosquitto MQTT broker gets Websockets support

A modern MQTT framework for .NET

https://github.com/somdoron/NetMQ.WebSockets

https://github.com/dude-seriously/gh12-server

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章