iOS_MQTT通訊協(xié)議

最近因為項目需要,需要用到MQTT通訊協(xié)議,上網了解了一下發(fā)現(xiàn)在物聯(lián)網這種協(xié)議經常使用。

E4470B6E-5855-4197-9625-F6BC66F9272D.png

MQTTClient的使用

iOS 環(huán)境下開發(fā) MQTT 客戶端程序,一般依賴穩(wěn)定的第三方 FrameWork,由于涉及網絡數據傳輸,建議選擇 Object-c 原生的框架,比如 MQTT-Client-Framework
現(xiàn)在一般常用的有兩個MQTT

  1. MQTTKit
  2. MQTTClient
不過MQTTKit貌似很長時間不維護了, 使用較多的是MQTTClient
  • 集成MQTTClient
    MQTT-Client-Framework

    • 用cocopod直接, pod ‘MQTTClient’
    • GitHub下載,把相對應的文件夾拖進工程即可

MQTT-Client-FrameWork 包提供的客戶端類有 MQTTSession 和 MQTTSessionManager,建議使用后者維持靜態(tài)資源,而且已經封裝好自動重連等邏輯。初始化時需要傳入相關的網絡參數。我使用的是第二種, 引入 #import "MQTTClient.h" #import "MQTTSessionManager.h" 頭文件, 遵循 MQTTSessionManagerDelegate協(xié)議

使用步驟一.

1.建立連接,和服務器端確定好MQTT服務器地址,端口號, 用戶名, 密碼, 訂閱主題topic

/**
      host: 服務器地址
      port: 服務器端口
      tls:  是否使用tls協(xié)議,mosca是支持tls的,如果使用了要設置成true
      keepalive: 心跳時間,單位秒,每隔固定時間發(fā)送心跳包, 心跳間隔不得大于120s
      clean: session是否清除,這個需要注意,如果是false,代表保持登錄,如果客戶端離線了再次登錄就可以接收到離線消息
      auth: 是否使用登錄驗證
      user: 用戶名
      pass: 密碼
      willTopic: 訂閱主題
      willMsg: 自定義的離線消息
      willQos: 接收離線消息的級別
      clientId: 客戶端id,需要特別指出的是這個id需要全局唯一,因為服務端是根據這個來區(qū)分不同的客戶端的,默認情況下一個id登錄后,假如有另外的連接以這個id登錄,上一個連接會被踢下線, 我使用的設備UUID
*/
NSString *clientId = [UIDevice currentDevice].identifierForVendor.UUIDString;
MQTTSessionManager *sessionManager = [[MQTTSessionManager alloc] init];
[sessionManager connectTo:@"121.199.19.126"  
                       port:1883
                        tls:false
                  keepalive:60  //心跳間隔不得大于120s
                      clean:true
                       auth:true
                       user:@"guest"
                       pass:@"guest"
                       will:false
                  willTopic:nil
                    willMsg:nil
                    willQos:0
             willRetainFlag:false
               withClientId:clientId];
    sessionManager.delegate = self;
    self.sessionManager = sessionManager;

2.監(jiān)控連接狀態(tài)
連接當前狀態(tài),添加對應的回調接口,可以進行相關的業(yè)務邏輯處理。

// 添加監(jiān)聽狀態(tài)觀察者
[self.sessionManager addObserver:self
                   forKeyPath:@"state"
                      options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                      context:nil];

監(jiān)聽連接狀態(tài),進行相應處理。

 // 監(jiān)聽當前連接狀態(tài)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    switch (self.sessionManager.state) {
        case MQTTSessionManagerStateClosed:
            NSLog(@"連接已經關閉");
            break;
        case MQTTSessionManagerStateClosing:
            NSLog(@"連接正在關閉");
 
            break;
        case MQTTSessionManagerStateConnected:
            NSLog(@"已經連接");
 
            break;
        case MQTTSessionManagerStateConnecting:
            NSLog(@"正在連接中");
 
            break;
        case MQTTSessionManagerStateError: {
            NSString *errorCode = self.sessionManager.lastErrorCode.localizedDescription;
            NSLog(@"連接異常 ----- %@",errorCode);
        }
 
            break;
        case MQTTSessionManagerStateStarting:
            NSLog(@"開始連接");
           break;
        default:
            break;
    }
}

3.接收消息 實現(xiàn)MQTTSessionManagerDelegate代理方法,處理數據

// 獲取服務器返回數據
- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained {
    NSLog(@"------------->>%@",topic);
 
    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",dataString);
 
     // 進行消息處理
}

4.訂閱和發(fā)送消息

// 訂閱主題    NSDictionary類型,Object 為 QoS,key 為 Topic
self.sessionManager.subscriptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:MQTTQosLevelExactlyOnce] forKey:@"hello"];
 
// 發(fā)送消息   返回值msgid大于0代表發(fā)送成功
NSString *msg = @"hahaha";
UInt16 msgid = [self.sessionManager sendData:[msg dataUsingEncoding:NSUTF8StringEncoding] //要發(fā)送的消息體
                                      topic:@"hello" //要往哪個topic發(fā)送消息
                                        qos:0 //消息級別
                                     retain:false];

阿里云的服務器

需要在阿里云控制臺申請 Topic,Group ID 等資源
在建立連接時,傳入的參數值也會有所改變, user 和 pass 由于服務端需要對客戶端進行鑒權,因此需要傳入合法的 user 和 pass。 user 設置為當前用戶的 AccessKey,pass 則設置為 MQTT 客戶端 GroupID 的簽名字符串,簽名計算方式是使用 SecretKey 對 GroupID 做 HmacSHA1 散列加密

self.manager = [[MQTTSessionManager alloc] init];
self.manager.delegate = self;
self.manager.subscriptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:self.qos]
                                                                 forKey:[NSString stringWithFormat:@"%@/#", self.rootTopic]];
//password的計算方式是,使用secretkey對groupId做hmac簽名算法,具體實現(xiàn)參考macSignWithText方法
NSString *passWord = [[self class] macSignWithText:self.groupId secretKey:self.secretKey];
[self.manager connectTo:self.mqttSettings[@"host"]
                                  port:[self.mqttSettings[@"port"] intValue]
                                   tls:[self.mqttSettings[@"tls"] boolValue]
                             keepalive:60  //心跳間隔不得大于120s
                                 clean:true
                                  auth:true
                                  user:self.accessKey
                                  pass:passWord
                                  will:false
                             willTopic:nil
                               willMsg:nil
                               willQos:0
                        willRetainFlag:false
                          withClientId:self.clientId];

使用 SecretKey 對 GroupID 做 HmacSHA1 散列加密

+ (NSString *)macSignWithText:(NSString *)text secretKey:(NSString *)secretKey {
    NSData *saltData = [secretKey dataUsingEncoding:NSUTF8StringEncoding];
    NSData *paramData = [text dataUsingEncoding:NSUTF8StringEncoding];
    NSMutableData* hash = [NSMutableData dataWithLength:CC_SHA1_DIGEST_LENGTH ];
    CCHmac(kCCHmacAlgSHA1, saltData.bytes, saltData.length, paramData.bytes, paramData.length, hash.mutableBytes);
    NSString *base64Hash = [hash base64EncodedStringWithOptions:0];
    return base64Hash;
}


參考文章
http://www.runoob.com/w3cnote/mqtt-intro.html
MQTT接入環(huán)境配置
阿里云接入MTQQ示例
申請MQ資源

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容