按照OSI網絡分層模型,IP是網絡層協議,TCP是傳輸層協議,而HTTP和MQTT是應用層的協議。在這三者之間, TCP是HTTP和MQTT底層的協議。大家對HTTP很熟悉,這里簡要介紹下MQTT。MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通訊協議,有可能成為物聯網的重要組成部分。該協議支持所有平臺,幾乎可以把所有聯網物品和外部連接起來,被用來當做傳感器的通信協議。
-
HTTP的不足
HTTP協議經過多年的使用,發現了一些不足,主要是性能方面的,包括:
HTTP的連接問題,HTTP客戶端和服務器之間的交互是采用請求/應答模式,在客戶端請求時,會建立一個HTTP連接,然后發送請求消息,服務端給出應答消息,然后連接就關閉了。(后來的HTTP1.1支持持久連接)
因為TCP連接的建立過程是有開銷的,如果使用了SSL/TLS開銷就更大。在瀏覽器里,一個網頁包含許多資源,包括HTML,CSS,JavaScript,圖片等等,這樣在加載一個網頁時要同時打開連接到同一服務器的多個連接。
HTTP消息頭問題,現在的客戶端會發送大量的HTTP消息頭,由于一個網頁可能需要50-100個請求,就會有相當大的消息頭的數據量。
HTTP通信方式問題,HTTP的請求/應答方式的會話都是客戶端發起的,缺乏服務器通知客戶端的機制,在需要通知的場景,如聊天室,游戲,客戶端應用需要不斷地輪詢服務器。
而 WebSocket是從不同的角度來解決這些不足中的一部分。還有其他技術也在針對這些不足提出改進。
-
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 Socket的API,是W3C的工作。
WebSocket可以只打開一個到服務器的鏈接,并且在此鏈接上交換信息。其優勢在于減少了傳統方法的復雜性,提高了可靠性和降低了瀏覽器和客戶端之間的負載。這樣做的一個重要原因是,很多防火墻屏蔽80以外的端口,迫使越來越多的應用遷移到HTTP上來了。
11年的websocket草案的變遷中,有的瀏覽器支持的是舊版本的websocket,比如iPhone4上的safari使用的WebSocket是舊版的握手協議,那么就要使用就的握手協議來制做服務器端。如今只有Safari支持舊版本的協議,Chrome和Firefox最新版都已升級至Hybi-10(協議地址)。因此,我們再來看一下WebSocket新版協議Hybi-10。這次協議變更非常大,主要集中在握手協議和數據傳輸的格式上。
握手協議
我們先來看一下大致的區別:
- 最老的websocket草案標準中是沒有安全key,草案7.5、7.6中有兩個安全key,而現在的草案10中只有一個安全key,即將 7.5、7.6中http頭中的"Sec-WebSocket-Key1″與"Sec-WebSocket-Key2″合并為了一個"Sec- WebSocket-Key"
- 把http頭中Upgrade的值由"WebSocket"修改為了"websocket";http頭中的"-Origin"修改為了"Sec-WebSocket-Origin";
- 增加了http頭"Sec-WebSocket-Accept",用來返回原來草案7.5、7.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;把N1和N2按照Big- Endian字符序列連接起來,然后再與另外一個Key3連接,得到一個原始序列ser_key。Key3是指在握手請求最后,有一個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==,用它和自定義的一個字符串(長度 36)258EAFA5-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... | +---------------------------------------------------------------+ |
FIN:1位,用來表明這是一個消息的最后的消息片斷,當然第一個消息片斷也可能是最后的一個消息片斷;
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:0或4個字節,客戶端發送給服務端的數據,都是通過內嵌的一個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協議衍生出來的各個不同版本。
MQTT和TCP、WebSocket的關系可以用下圖一目了然:
MQTT協議專注于網絡、資源受限環境,建立之初不曾考慮WEB環境。HTML5 Websocket是建立在TCP基礎上的雙通道通信,和TCP通信方式很類似,適用于WEB瀏覽器環境。雖然MQTT基因層面選擇了TCP作為通信通道,但我們添加個編解碼方式,MQTT over Websocket也可以的。這樣做的好處,MQTT的使用范疇被擴展到HTML5、桌面端瀏覽器、移動端WebApp、Hybrid等,多了一些想像空間。這樣看來,無論是移動端,還是WEB端,MQTT都會有自己的使用空間。
一步一步學WebSocket (一) 初識WebSocket
一步一步學WebSocket(二) 使用SuperWebSocket實現自己的服務端
Websocket全講解。跨平臺的通訊協議!!基于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學習筆記——MQTT協議體驗 Mosquitto安裝和使用
The Mosquitto MQTT broker gets Websockets support
A modern MQTT framework for .NET
文章列表
留言列表