MQTTClient的使用介紹

開篇


最近在使用MQTTClient實(shí)現(xiàn)一個(gè)類似于消息推送的服務(wù)怠惶,說(shuō)實(shí)話躺枕,真沒怎么使用過(guò)MQTTClient苏遥,也不知道這是個(gè)啥奸例? 好尷尬 ?? ?? ?? 上網(wǎng)了解了一下彬犯,發(fā)現(xiàn)MQTT功能挺強(qiáng)(牛)大(逼)。這里我使用的是消息推送服務(wù)查吊,通過(guò)和服務(wù)器端協(xié)商谐区,終于能夠與服務(wù)器連接,并且能夠收發(fā)消息了逻卖。 所以宋列,簡(jiǎn)單總結(jié)了一下,有了這篇文章评也。

MQTT介紹


  • MQTT
    MQTT基于訂閱者模型架構(gòu)炼杖,客戶端如果互相通信,必須在同一訂閱主題下盗迟,即都訂閱了同一個(gè)topic坤邪,客戶端之間是沒辦法直接通訊的。訂閱模型顯而易見的好處是群發(fā)消息的話只需要發(fā)布到topic罚缕,所有訂閱了這個(gè)topic的客戶端就可以接收到消息了艇纺。
    發(fā)送消息必須發(fā)送到某個(gè)topic,重點(diǎn)說(shuō)明的是不管客戶端是否訂閱了該topic都可以向topic發(fā)送了消息邮弹,還有如果客戶端訂閱了該主題黔衡,那么自己發(fā)送的消息也會(huì)接收到。
  • MQTT特點(diǎn)
    • 使用發(fā)布/訂閱消息模式腌乡,提供一對(duì)多的消息發(fā)布盟劫,解除應(yīng)用程序耦合。這一點(diǎn)很類似于XMPP导饲,但是MQTT的信息冗余遠(yuǎn)小于XMPP.

    • 對(duì)負(fù)載內(nèi)容屏蔽的消息傳輸捞高。
      使用TCP/IP提供網(wǎng)絡(luò)連接。主流的MQTT是基于TCP連接進(jìn)行數(shù)據(jù)推送的渣锦,但是同樣有基于UDP的版本硝岗,叫做MQTT-SN。這兩種版本由于基于不同的連接方式袋毙,優(yōu)缺點(diǎn)自然也就各有不同了型檀。

    • 三種消息傳輸方式QoS:

      • 0代表“至多一次”,消息發(fā)布完全依賴底層 TCP/IP 網(wǎng)絡(luò)听盖。會(huì)發(fā)生消息丟失或重復(fù)赋访。這一級(jí)別可用于如下情況坠非,環(huán)境傳感器數(shù)據(jù),丟失一次讀記錄無(wú)所謂,因?yàn)椴痪煤筮€會(huì)有第二次發(fā)送答姥。
      • 1代表“至少一次”,確保消息到達(dá)趟大,但消息重復(fù)可能會(huì)發(fā)生门粪。
      • 2代表“只有一次”,確保消息到達(dá)一次毛雇。這一級(jí)別可用于如下情況嫉称,在計(jì)費(fèi)系統(tǒng)中,消息重復(fù)或丟失會(huì)導(dǎo)致不正確的結(jié)果灵疮。 (備注:由于服務(wù)端采用Mosca實(shí)現(xiàn)织阅,Mosca目前只支持到QoS 1)

      如果發(fā)送的是臨時(shí)的消息,例如給某topic所有在線的設(shè)備發(fā)送一條消息震捣,丟失的話也無(wú)所謂荔棉,0就可以了(客戶端登錄的時(shí)候要指明支持的QoS級(jí)別,同時(shí)發(fā)送消息的時(shí)候也要指明這條消息支持的QoS級(jí)別)蒿赢,如果需要客戶端保證能接收消息江耀,需要指定QoS為1,如果同時(shí)需要加入客戶端不在線也要能接收到消息诉植,那么客戶端登錄的時(shí)候要指定session的有效性祥国,接收離線消息需要指定服務(wù)端要保留客戶端的session狀態(tài)。

具體MQTT的詳細(xì)介紹可以戳這里 https://baike.baidu.com/item/MQTT/3618851?fr=aladdin

MQTTClient的使用


iOS 環(huán)境下開發(fā) MQTT 客戶端程序晾腔,一般依賴穩(wěn)定的第三方 FrameWork舌稀,由于涉及網(wǎng)絡(luò)數(shù)據(jù)傳輸,建議選擇 Object-c 原生的框架灼擂,比如 MQTT-Client-Framework壁查。
現(xiàn)在一般常用的有兩個(gè)MQTT
1) MQTTKit
2) MQTTClient
不過(guò)MQTTKit貌似很長(zhǎng)時(shí)間不維護(hù)了, 使用較多的是MQTTClient剔应。

  • 集成MQTTClient
    MQTT-Client-Framework
    • 用cocopod直接睡腿, pod 'MQTTClient'
    • GitHub下載语御,把相對(duì)應(yīng)的文件夾拖進(jìn)工程即可

MQTT-Client-FrameWork 包提供的客戶端類有 MQTTSessionMQTTSessionManager,建議使用后者維持靜態(tài)資源席怪,而且已經(jīng)封裝好自動(dòng)重連等邏輯应闯。初始化時(shí)需要傳入相關(guān)的網(wǎng)絡(luò)參數(shù)。

我使用的是第二種挂捻, 引入 #import "MQTTClient.h" #import "MQTTSessionManager.h" 頭文件碉纺, 遵循 MQTTSessionManagerDelegate協(xié)議

使用步驟:

  • 建立連接
    和服務(wù)器端確定好MQTT服務(wù)器地址,端口號(hào)刻撒, 用戶名骨田, 密碼, 訂閱主題topic
/**
      host: 服務(wù)器地址
      port: 服務(wù)器端口
      tls:  是否使用tls協(xié)議声怔,mosca是支持tls的态贤,如果使用了要設(shè)置成true
      keepalive: 心跳時(shí)間,單位秒醋火,每隔固定時(shí)間發(fā)送心跳包, 心跳間隔不得大于120s
      clean: session是否清除抵卫,這個(gè)需要注意,如果是false胎撇,代表保持登錄介粘,如果客戶端離線了再次登錄就可以接收到離線消息
      auth: 是否使用登錄驗(yàn)證
      user: 用戶名
      pass: 密碼
      willTopic: 訂閱主題
      willMsg: 自定義的離線消息
      willQos: 接收離線消息的級(jí)別
      clientId: 客戶端id,需要特別指出的是這個(gè)id需要全局唯一晚树,因?yàn)榉?wù)端是根據(jù)這個(gè)來(lái)區(qū)分不同的客戶端的姻采,默認(rèn)情況下一個(gè)id登錄后,假如有另外的連接以這個(gè)id登錄爵憎,上一個(gè)連接會(huì)被踢下線, 我使用的設(shè)備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;
  • 監(jiān)控連接狀態(tài)
    連接當(dāng)前狀態(tài)慨亲,添加對(duì)應(yīng)的回調(diào)接口,可以進(jìn)行相關(guān)的業(yè)務(wù)邏輯處理宝鼓。
// 添加監(jiān)聽狀態(tài)觀察者
[self.sessionManager addObserver:self
                   forKeyPath:@"state"
                      options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                      context:nil];

監(jiān)聽連接狀態(tài)刑棵,進(jìn)行相應(yīng)處理。

 // 監(jiān)聽當(dāng)前連接狀態(tài)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    switch (self.sessionManager.state) {
        case MQTTSessionManagerStateClosed:
            NSLog(@"連接已經(jīng)關(guān)閉");
            break;
        case MQTTSessionManagerStateClosing:
            NSLog(@"連接正在關(guān)閉");

            break;
        case MQTTSessionManagerStateConnected:
            NSLog(@"已經(jīng)連接");

            break;
        case MQTTSessionManagerStateConnecting:
            NSLog(@"正在連接中");

            break;
        case MQTTSessionManagerStateError: {
            NSString *errorCode = self.sessionManager.lastErrorCode.localizedDescription;
            NSLog(@"連接異常 ----- %@",errorCode);
        }

            break;
        case MQTTSessionManagerStateStarting:
            NSLog(@"開始連接");
           break;
        default:
            break;
    }
}

  • 接收消息
    實(shí)現(xiàn)MQTTSessionManagerDelegate代理方法愚铡,處理數(shù)據(jù)蛉签。
// 獲取服務(wù)器返回?cái)?shù)據(jù)
- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained {
    NSLog(@"------------->>%@",topic);
    
    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",dataString);
    
     // 進(jìn)行消息處理
}

  • 訂閱和發(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" //要往哪個(gè)topic發(fā)送消息
                                        qos:0 //消息級(jí)別
                                     retain:false];

如果是使用阿里云的服務(wù)器替代自己的服務(wù)器碍舍,需要在阿里云控制臺(tái)申請(qǐng) TopicGroup ID 等資源邑雅。
在建立連接時(shí)片橡,傳入的參數(shù)值也會(huì)有所改變, userpass 由于服務(wù)端需要對(duì)客戶端進(jìn)行鑒權(quán)淮野,因此需要傳入合法的 userpass捧书。 user 設(shè)置為當(dāng)前用戶的 AccessKey吹泡,pass 則設(shè)置為 MQTT 客戶端 GroupID 的簽名字符串,簽名計(jì)算方式是使用 SecretKey 對(duì) GroupIDHmacSHA1 散列加密经瓷。

       self.manager = [[MQTTSessionManager alloc] init];
        self.manager.delegate = self;
        self.manager.subscriptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:self.qos]
                                                                 forKey:[NSString stringWithFormat:@"%@/#", self.rootTopic]];
        //password的計(jì)算方式是爆哑,使用secretkey對(duì)groupId做hmac簽名算法,具體實(shí)現(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 對(duì) GroupIDHmacSHA1 散列加密

+ (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;
}

具體介紹請(qǐng)戳下面幫助鏈接
MQTT接入環(huán)境配置
阿里云接入MTQQ示例
申請(qǐng)MQ資源

參考


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末了嚎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子廊营,更是在濱河造成了極大的恐慌歪泳,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件露筒,死亡現(xiàn)場(chǎng)離奇詭異呐伞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)慎式,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門伶氢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瘪吏,你說(shuō)我怎么就攤上這事癣防。” “怎么了掌眠?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蕾盯,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蓝丙,道長(zhǎng)级遭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任渺尘,我火速辦了婚禮挫鸽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸥跟。我一直安慰自己丢郊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布医咨。 她就那樣靜靜地躺著蚂夕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腋逆。 梳的紋絲不亂的頭發(fā)上婿牍,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音惩歉,去河邊找鬼等脂。 笑死俏蛮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的上遥。 我是一名探鬼主播搏屑,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼粉楚!你這毒婦竟也來(lái)了辣恋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤模软,失蹤者是張志新(化名)和其女友劉穎伟骨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燃异,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡携狭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了回俐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逛腿。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仅颇,靈堂內(nèi)的尸體忽然破棺而出单默,到底是詐尸還是另有隱情,我是刑警寧澤忘瓦,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布雕凹,位于F島的核電站,受9級(jí)特大地震影響政冻,放射性物質(zhì)發(fā)生泄漏枚抵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一明场、第九天 我趴在偏房一處隱蔽的房頂上張望汽摹。 院中可真熱鬧,春花似錦苦锨、人聲如沸逼泣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拉庶。三九已至,卻和暖如春秃励,著一層夾襖步出監(jiān)牢的瞬間氏仗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工夺鲜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皆尔,地道東北人呐舔。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像慷蠕,于是被迫代替她去往敵國(guó)和親珊拼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理流炕,服務(wù)發(fā)現(xiàn)澎现,斷路器,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • MQTT-SN的一個(gè)重要設(shè)計(jì)原則是盡可能與MQTT相近每辟。因此剑辫,所有的協(xié)議語(yǔ)義應(yīng)保持盡可能與MQTT中定義的一致。接...
    aded3e27ac95閱讀 848評(píng)論 0 2
  • 序 本篇會(huì)把連接(CONNECT)影兽、心跳(PINGREQ/PINGRESP)揭斧、確認(rèn)(CONNACK)莱革、斷開連接(D...
    技術(shù)學(xué)習(xí)閱讀 9,726評(píng)論 0 8
  • MQTT Protocol MQTT協(xié)議特性 一句話總結(jié):MQTT是一個(gè)簡(jiǎn)單峻堰,輕量的消息發(fā)布/訂閱協(xié)議。 MQTT...
    钢咽樱克斯記閱讀 7,234評(píng)論 0 9
  • 酒這玩意兒日怪捐名,給錢不算,還須問(wèn)到身體賒賬闹击。償還更莫談錢镶蹋,——他龜兒要的是時(shí)間。這不赏半,前晚和阿野還有幾個(gè)美女喝酒到...
    湯沅霖閱讀 1,561評(píng)論 0 3