iOS開發之MQTT探究

一、 什麼是MQTT?

MQTT(MessageQueueing Telemetry Transport Protocol)的全稱是消息隊列遙感傳輸協議的縮寫,是由IBM公司推出的一種基於輕量級代理的發佈/訂閱模式的消息傳輸協議,運行在TCP協議棧之上,爲其提供有序、可靠、雙向鏈接的網絡鏈接保證。因爲其開放、簡單和易於實現因此可以應用在資源受限的環境中,對於M2M和物聯網應用程序來講是一個至關不錯的選擇。服務器

二、 爲何要用MQTT?

MQTT協議是針對以下狀況設計的:網絡

M2M(Machine to Machine) communication,機器端到端通訊,好比傳感器之間的數據通信 由於是Machine to Machine,須要考慮: Machine,或者叫設備,好比溫度傳感器,硬件能力很弱,協議要考慮儘可能小的資源消耗,好比計算能力和存儲等 M2M多是無線鏈接,網絡不穩定,帶寬也比較小session

MQTT的特色:架構

  1. 發佈/訂閱消息模式,提供一對多的消息發佈,解除應用程序耦合。這一點很相似於1. 這裏是列表文本XMPP,可是MQTT的信息冗餘遠小於XMPP.
  2. 對負載內容屏蔽的消息傳輸。
  3. 使用TCP/IP提供網絡鏈接。主流的MQTT是基於TCP鏈接進行數據推送的,可是一樣有基於UDP的版本,叫作MQTT-SN。這兩種版本因爲基於不一樣的鏈接方式,優缺點天然也就各有不一樣了。
  4. 三種消息傳輸方式QoS:
  • 0表明「至多一次」,消息發佈徹底依賴底層 TCP/IP 網絡。會發生消息丟失或重複。這一級別可用於以下狀況,環境傳感器數據,丟失一次讀記錄無所謂,由於不久後還會有第二次發送。app

  • 1表明「至少一次」,確保消息到達,但消息重複可能會發生。框架

  • 2表明「只有一次」,確保消息到達一次。這一級別可用於以下狀況,在計費系統中,消息重複或丟失會致使不正確的結果。 備註:因爲服務端採用Mosca實現,Mosca目前只支持到QoS 1eclipse

  • 若是發送的是臨時的消息,例如給某topic全部在線的設備發送一條消息,丟失的話也無所謂,0就能夠了(客戶端登陸的時候要指明支持的QoS級別,同時發送消息的時候也要指明這條消息支持的QoS級別),若是須要客戶端保證能接收消息,須要指定QoS爲1,若是同時須要加入客戶端不在線也要能接收到消息,那麼客戶端登陸的時候要指定session的有效性,接收離線消息須要指定服務端要保留客戶端的session狀態。async

  • mqtt基於訂閱者模型架構,客戶端若是互相通訊,必須在同一訂閱主題下,即都訂閱了同一個topic,客戶端之間是沒辦法直接通信的。訂閱模型顯而易見的好處是羣發消息的話只須要發佈到topic,全部訂閱了這個topic的客戶端就能夠接收到消息了。ide

  • 發送消息必須發送到某個topic,重點說明的是無論客戶端是否訂閱了該topic均可以向topic發送了消息,還有若是客戶端訂閱了該主題,那麼本身發送的消息也會接收到。ui

  1. 小型傳輸,開銷很小(固定長度的頭部是2字節),協議交換最小化,以下降網絡流量。這就是爲何在介紹裏說它很是適合「在物聯網領域,傳感器與服務器的通訊,信息的收集」,要知道嵌入式設備的運算能力和帶寬都相對薄弱,使用這種協議來傳遞消息再適合不過了。
  2. 使用Last Will和Testament特性通知有關各方客戶端異常中斷的機制。Last Will:即遺言機制,用於通知同一主題下的其餘設備發送遺言的設備已經斷開了鏈接。Testament:遺囑機制,功能相似於Last Will 。

三、 怎麼使用MQTT

在mac上搭建MQTT服務器

$ brew install mosquitto

等待下載完成,服務會自動運行起來

mosquitto has been installed with a default configuration file.
You can make changes to the configuration by editing:
    /usr/local/etc/mosquitto/mosquitto.conf

To have launchd start mosquitto now and restart at login:
  brew services start mosquitto
Or, if you don't want/need a background service you can just run:
  mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf

iOS client註冊

#import "ViewController.h"

#define kMQTTServerHost @"iot.eclipse.org"
#define kTopic @"MQTTExample/Message"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *showMessage;
@property (nonatomic, strong) MQTTClient *client;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //1.在app登陸後,後臺返回 name+password+topic
    
    //2.name+password用於鏈接主機
    
    //3.topic 用於訂閱主題
    

    UILabel *tempShowMessage = self.showMessage;
    
    NSString *clientID = [UIDevice currentDevice].identifierForVendor.UUIDString;
    
    self.client = [[MQTTClient alloc] initWithClientId:clientID];

    //鏈接服務器  鏈接後,會經過block將鏈接結果code返回,而後執行此段代碼塊
    
    //這個接口是修改事後的接口,修改後拋出了name+password
    [self.client connectToHost:kMQTTServerHost andName:@"cbt" andPassword:@"1223" completionHandler:^(MQTTConnectionReturnCode code) {
        if (code == ConnectionAccepted)//鏈接成功
        {
            // 訂閱
            [self.client subscribe:kTopic withCompletionHandler:^(NSArray *grantedQos) {
                // The client is effectively subscribed to the topic when this completion handler is called
                NSLog(@"subscribed to topic %@", kTopic);
                NSLog(@"return:%@",grantedQos);
            }];
        }
    }];
    
    
    //MQTTMessage  裏面的數據接收到的是二進制,這裏框架將其封裝成了字符串
    [self.client setMessageHandler:^(MQTTMessage* message)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            //接收到消息,更新界面時須要切換回主線程
            tempShowMessage.text= message.payloadString;
        });
    }];  
    
}


- (void)dealloc8
{
    // disconnect the MQTT client
    [self.client disconnectWithCompletionHandler:^(NSUInteger code)
    {
        // The client is disconnected when this completion handler is called
        NSLog(@"MQTT is disconnected");
    }];
}
@end

server向client推送消息

#import "ViewController.h"
#import "MQTTKit.h"


#define kMQTTServerHost @"iot.eclipse.org"
#define kTopic @"MQTTExample/Message"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *pushMessage;
@property (nonatomic, strong) MQTTClient *client;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    NSString *clientID = [UIDevice currentDevice].identifierForVendor.UUIDString;
    
    self.client = [[MQTTClient alloc] initWithClientId:clientID];
    [self.client connectToHost:kMQTTServerHost andName:@"cbt" andPassword:@"1223" completionHandler:^(MQTTConnectionReturnCode code) {
        if (code == ConnectionAccepted)
        {
            NSLog(@"服務器啓動成功");
        }
    }];
    
    
}

- (IBAction)push:(id)sender {
    NSString* payload = self.pushMessage.text;
    [self.client publishString:payload
                       toTopic:kTopic
                       withQos:AtMostOnce
                        retain:YES
             completionHandler:nil];
    NSLog(@"推送內容:%@",payload);
}
相關文章
相關標籤/搜索