http://blog.wuzx.me/archives/102
2014
最近在折騰Android的推送,看到相關資料說可以用MQTT協議實現。所以就去查相關的資料,并展開相關知識了解,折騰了幾天。
MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通訊協議。
MQTT協議是為大量計算能力有限,且工作在低帶寬、不可靠的網絡的遠程傳感器和控制設備通訊而設計的協議,它具有以下主要的幾項特性
1、使用發布(Publish)/訂閱/(Subscribe)消息模式,提供一對多的消息發布,解除應用程序耦合
2、對負載內容屏蔽的消息傳輸
3、使用_TCP/IP_提供網絡連接
4、有三種消息發布服務質量
“至多一次”,消息發布完全依賴底層 TCP/IP 網絡。會發生消息丟失或重復。這一級別可用于如下情況,環境傳感器數據,丟失一次讀記錄無所謂,因為不久后還會有第二次發送。
“至少一次”,確保消息到達,但消息重復可能會發生。
“只有一次”,確保消息到達一次。這一級別可用于如下情況,在計費系統中,消息重復或丟失會導致不正確的結果。
5、小型傳輸,開銷很小(固定長度的頭部是 2 字節),協議交換最小化,以降低網絡流量
6、使用 Last Will 和 Testament 特性通知有關各方客戶端異常中斷的機制
參考百度百科MQTT
MQTT協議的實現,自然要分為客戶端(Client)和服務端(Broker)。服務端也被稱為代理,Broker。
服務端,或者叫代理(Broker),有很多,見下圖。
這些服務端有重有輕,有些是開源的,有些是企業級公司的收費產品。
像有些是IBM的一些產品框架,是要收費的。
當然也有一些開源的輕量級Broker,還有Apache的一些開源產品。
“XXX over yyy” 的意思是在yyy的基礎上實現XXX。
比如MQTT over WebSocket
是指在WebSocket的基礎上實現MQTT協議。
前面在說特點的時候,原生的MQTT協議應該是在運輸層 TCP/IP協議的基礎上的應用層協議。單獨來看,WebSocket也是應用層的一個協議,是在TCP的基礎上的一個全雙工通道通信。 但是為了能在瀏覽器(瀏覽器只支持WebSocket這種全雙工應用層協議,客戶端用js實現,現在大部分瀏覽器都支持)上實現MQTT協議,就把WebSocket協議當做傳輸層的TCP/IP的角色,讓MQTT跑在WebSocket協議上。
雖然MQTT基因層面選擇了TCP作為通信通道,但我們添加個編解碼方式,MQTT Over Websocket也可以的
參考MQTT協議筆記之mqtt.io項目Websocket協議支持
類似的跑在別的協議之上的協議的實現還有很多,盡管兩者協議在性質上是平級的,都是應用層的協議
當然Broker也要能支持這種模式。有些Broker是可以接受跑在WebSocket上的MQTT協議的實現,有些則不支持,只支持原生在TCP協議基礎上的實現。
所以這種的服務端就不能被JS實現的客戶端連接。 服務端支不支持WebSocket的這種模式,可以看Broker的介紹里有沒有說。
客戶端(Client)除了JS的實現,其他的基本都是在TCP/IP協議基礎上的,JS的實現是應該在瀏覽器上的,所以要在瀏覽器已實現的協議上實現MQTT協議,而WebSocket是最符合的。
這個模塊先講到這,下面內容還會回來用到。下面先講個Broker的實例
說了這么多,看個實例 這里有個叫Mosquitto(這不是蚊子嗎?蚊子是mosquito)
是一個開源的MQTT v3.1 Broker 這個Broker只有幾百k,貌似是MQTT協議的創始人用C寫的,非常精簡,功能也非常強大。網上有朋友測過,可以承受20000人同時在線,自己還沒測過,有空可以測一下。并且這個服務端有提供網橋功能。大概的意思是可以把服務器連在一起吧
Mosquitto 啟動的時候有一個配置文件,在這個配置文件里可以設置一些參數,通過這些參數設定連接的一些條件和機制,比如timeout相關的和安全相關的認證機制。啟動之后,服務器就可以開著,然后就通過客戶端實現消息的發布(Publish)和訂閱(Subscribe)
Eclipse有一個開源項目叫Paho,就是一個實現MQTT協議客戶端的項目,它實現了好多語言的客戶端的封裝(甚至有嵌入式),還有一些工具(utilities)只要按照它的實例開發,很方便,并且文檔很全。
再次感謝開源項目,OpenSource精神
所以Android要實現推送,這里有現成的客戶端。服務器就用Mosquitto,基本就差不多了。不過我還沒親測大用戶量的情況。
關于Mosquito的使用,比如參數配置,還有客戶端的實例編程,先不具體放代碼,換一篇單獨詳細介紹。
在我的項目中,Android打算用前面說的架構實現推送,就是Broker用Mosquitto,客戶端用Paho的Android Client。但是Mosquitto是不支持Websocket的,所以Web端要實現推送就不能用同一個服務器。(原因前面節講過了)(之前不知道,我試了好久WEB端上用JS連接Mosquitto,就是連不上,然后客戶端打出錯誤代碼和信息,在Google上查了很久,才知道不支持Websocket。也查到了下面的一種代理方法來實現)
所以如果要實現Web的推送,要么就單純在WebSocket上實現消息傳遞,現在的一些Web服務器都有實現這個,比如Tomcat7以后就有Websocket編程接口。但是這樣推送服務端就有兩個,貌似不是很統一。
其實要MQTT服務器實現基于Websocket的連接也不是不可以。
一套服務端程序,同時提供若干種協議供終端選擇。其實,一臺MQTT Broker中間件服務器,可以綁定多個端口,一個面向純TCP的1883端口,一個面向Websocket的80/8080端口,共享基礎邏輯,面向不同協議。
但是這個方法在Mosquitto這個Broker上不好實現,因為這個用C寫的,難度有點大。
有另一個MQTT的Broker是用Java寫的叫Moquette
(不要看錯,和Mosquitto有點像)。它是一個Jar包,可以直接跑jar包,也可以寫入自己的程序跑。所以添加一些代碼相對比較容易,又因為是Java,編程接口和庫比較豐富。但是前提是你能看懂Moquette的源碼。
下面繼續參考聶永的博客,里面有Java的實現。但他的MQTT服務器不是Moquette,所以代碼什么的不完全一樣。但原理是一樣的。所以僅供參考。
參考MQTT協議筆記之mqtt.io項目Websocket協議支持
原理圖如下
簡單的理解就是瀏覽器用WebSocket協議跟前端的服務器連接,而前端的服務器用TCP協議和后端的MQTT服務器連接。然后瀏覽器在Websocket的連接之上傳遞的內容,經過代理轉到后端的MQTT服務器。
中間的代理剝掉了承載MQTT協議的Websocket協議外殼,然后把內容經過TCP包裹發給了后端的MQTT服務器
其實以上過程就是一個反向代理,在網絡中很常見的手法。什么是反向代理,請自行查詢資料。
綜上這兩種方法都可以讓不支持Websocket的MQTT的Broker實現和Web端的JS的Client通信。
因為現在的網絡架構Web服務器的第一層一般都會用Nginx實現反向代理,所以我應該會選擇第二種方法。用Nginx實現Websocket–TCP代理,具體實現還沒去研究,等搞定了放在反向代理的一篇博客里好了。
但就業務邏輯來講,這么做的目的是為了Android的推送和Web的推送實現服務端的統一。如果Web的推送不用MQTT協議也是可行的,直接在Websocket上實現,前面也提過了。
Mosquitto的運用的自己的完整例子,后續使用時再做總結。
如有不對的地方,歡迎交流。 (完)