最近因為項目需要,需要用到MQTT通訊協(xié)議
,上網了解了一下發(fā)現(xiàn)在物聯(lián)網這種協(xié)議經常使用。
MQTTClient的使用
iOS 環(huán)境下開發(fā) MQTT 客戶端程序,一般依賴穩(wěn)定的第三方 FrameWork,由于涉及網絡數據傳輸,建議選擇 Object-c 原生的框架,比如 MQTT-Client-Framework
。
現(xiàn)在一般常用的有兩個MQTT
- MQTTKit
- 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資源