先來引用一下網上對mqtt的理解:MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協議),是一種基于發布/訂閱(publish/subscribe)模式的“輕量級”通訊協議,該協議構建于TCP/IP協議上,由IBM在1999年發布。MQTT最大優點在于,可以以極少的代碼和有限的帶寬,為連接遠程設備提供實時可靠的消息服務。作為一種低開銷、低帶寬占用的即時通訊協議,使其在物聯網、小型設備、移動應用等方面有較廣泛的應用。
MQTT是一個基于客戶端-服務器的消息發布/訂閱傳輸協議。MQTT協議是輕量、簡單、開放和易于實現的,這些特點使它適用范圍非常廣泛。在很多情況下,包括受限的環境中,如:機器與機器(M2M)通信和物聯網(IoT)。其在,通過衛星鏈路通信傳感器、偶爾撥號的醫療設備、智能家居、及一些小型化設備中已廣泛使用。
特性
MQTT協議工作在低帶寬、不可靠的網絡的遠程傳感器和控制設備通訊而設計的協議,它具有以下主要的幾項特性:
(1)使用發布/訂閱消息模式,提供一對多的消息發布,解除應用程序耦合。
這一點很類似于XMPP,但是MQTT的信息冗余遠小于XMPP,,因為XMPP使用XML格式文本來傳遞數據。
(2)對負載內容屏蔽的消息傳輸。**
(3)使用TCP/IP提供網絡連接。**
主流的MQTT是基于TCP連接進行數據推送的,但是同樣有基于UDP的版本,叫做MQTT-SN。這兩種版本由于基于不同的連接方式,優缺點自然也就各有不同了。
(4)有三種消息發布服務質量:**
“至多一次”,消息發布完全依賴底層TCP/IP網絡。會發生消息丟失或重復。這一級別可用于如下情況,環境傳感器數據,丟失一次讀記錄無所謂,因為不久后還會有第二次發送。這一種方式主要普通APP的推送,倘若你的智能設備在消息推送時未聯網,推送過去沒收到,再次聯網也就收不到了。
“至少一次”,確保消息到達,但消息重復可能會發生。
“只有一次”,確保消息到達一次。在一些要求比較嚴格的計費系統中,可以使用此級別。在計費系統中,消息重復或丟失會導致不正確的結果。這種最高質量的消息發布服務還可以用于即時通訊類的APP的推送,確保用戶收到且只會收到一次。
(5)小型傳輸,開銷很小(固定長度的頭部是2字節),協議交換最小化,以降低網絡流量。**
這就是為什么在介紹里說它非常適合“在物聯網領域,傳感器與服務器的通信,信息的收集”,要知道嵌入式設備的運算能力和帶寬都相對薄弱,使用這種協議來傳遞消息再適合不過了。
(6)使用Last Will和Testament特性通知有關各方客戶端異常中斷的機制。
好了,到此網上引用的介紹就完了,更詳細的可以百度一下,有很多人對它的介紹非常詳細。接下來我就說說我的學習過程及應用。先來分析一下官方的結構原理圖。原理圖
從圖中可以看到MQTT協議中有三種身份:發布者(Publish)、代理(Broker)(服務器)、訂閱者(Subscribe)。其中,消息的發布者和訂閱者都是客戶端,消息代理是服務器,消息發布者可以同時是訂閱者。
也就說我們只要建立中間的代理者(即服務器與我們自己學習開發用的Tomcat不要混覺),這個代理有個名字叫做broker,就可以使任意訂閱者之間進行訂閱和推送關系的傳輸。
相對于上面的結構我們開發可能更傾向于下面這種結構模式,在學習過程中我也做過這種模式測試,喜歡的朋友可以去測試,由于所有開發并不是我一個人完成,所以在這里并沒有全部的代碼。
說明一下,圖中所示的app,只是一個訂閱者與發布者,它可以是網頁腳本等其他支持mqtt協議的開發的終端。而這里我們的目的主要是實現把從硬件獲取的數據提交給app端和寫入數據庫端,其中Client這里用的是我們自己寫的Tomcat服務器來與數據進行連接,也作為集訂閱者和發布者為一身的身份,這樣的好處就是,在這么多終端中,完全不用理會其他終端給誰發送了什么和數據怎么送到另一個終端,而終端只需關注自己需要哪些數據,只需去訂閱相關的topic,就能收到另一個發出來的數據,這就相當于終端把數據放到broker里,哪個終端需要就去拿。任意兩個終端的數據傳輸都是不影響的,也不用去刻意去實現某兩個終端間的連接,只需要訂閱相同的推送話題就行了,任何終端都可以獲取同一數據。
實現過程
1、安裝broker
只需下載Apache apollo安裝并啟動就是一個broker了,至于怎么安裝可以網上找一下教程,也不難安裝。
2、安裝好在cdm啟動broker
啟動界面.jpg
3、在瀏覽器輸入http://127.0.0.1:61680/并登錄broker,找到配置文件那里,查看或者修改你的topic的ip和端口號。ip和端口查看.png
3、寫一個客戶端,這個客戶端可以是WiFi模塊、Tomcat服務器程序、java 程序、APP等等都是客戶端,所以這里使用java 來演示一下與broker進行連接。
package mqtt.client;
import mqtt.server.PushCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class mqttclient {
public static void main(String[] arg) throws MqttException{
String HOST = "tcp://x.x.x.x:xxxx"; //ip和端口
String topic = "totest"; //訂閱的主題
String clientid = "server";
String userName = "admin"; //非必須項
String passWord = "password"; //非必須項
MqttClient sampleClient = new MqttClient(HOST, clientid, new MemoryPersistence());
MqttConnectOptions connOpts = new MqttConnectOptions();
//
connOpts.setAutomaticReconnect(true);
//
connOpts.setCleanSession(false);
connOpts.setKeepAliveInterval(80);//
sampleClient.setCallback(new PushCallback()); //設置消息回調,即接收訂閱消息
//進行連接到broker
sampleClient.connect(connOpts);
//訂閱話題
sampleClient.subscribe("time",2);
/*MqttTopic totset= sampleClient.getTopic(topic);*/
System.out.println("test");
}
}
消息回調類的實現
package mqtt.server;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
//連接成功進行回調的類
public class PushCallback implements MqttCallback {
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
// publish后會執行到這里
System.out.println("deliveryComplete---------"+ token.isComplete());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
// TODO Auto-generated method stub
System.out.println("接收消息主題:"+topic);
System.out.println("接收消息Qos:"+message.getQos());
System.out.println("接收消息內容:"+new String(message.getPayload()));
}
@Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
// 連接丟失后,一般在這里面進行重連
System.out.println("連接斷開,可以做重連");
}
}
本文只是入門程序,這里不深入講解,有疑問可留言交流。