最近公司實(shí)現(xiàn)實(shí)時(shí)傳輸數(shù)據(jù),使用的是MQTT實(shí)現(xiàn)的,接下來描述一下內(nèi)容,當(dāng)作是筆記了
一. MQTT
一個(gè)物聯(lián)網(wǎng)項(xiàng)目中用到了MQTT協(xié)議, 可以用來做設(shè)備與軟件之間的互通.
MQTT: 即時(shí)通訊協(xié)議, 傳輸層協(xié)議
二. 常用:
1.MQTTKit(已經(jīng)不維護(hù)了)
2.MQTTClient
a.設(shè)置地址端口, 賬號(hào)密碼等基本信息
b.訂閱主題(可以訂閱多個(gè)主題)
c.實(shí)現(xiàn)代理回調(diào)方法(處理數(shù)據(jù))
三. 三種消息傳輸方式:(看情況使用)
a.至多一次 (會(huì)發(fā)生消息丟失或重復(fù))
b.至少一次 (確保消息到達(dá), 會(huì)發(fā)生消息重復(fù))
c.只有一次 (確保消息到達(dá)一次)
四、引入庫
pod 'MQTTClient'
pod 'MQTTClient/Min'
pod 'MQTTClient/Manager'
pod 'MQTTClient/Websocket'
這里采用的是MQTTClient開源庫開發(fā)。如果后臺(tái)的MQTT服務(wù)用的ws,則還需要導(dǎo)入pod 'MQTTClient/Websocket',此處根據(jù)自身需要pod即可。
五、 代碼:
#import <MQTTClient/MQTTClient.h>
#import <MQTTClient/MQTTSessionManager.h>
配置基本信息
- (void)setParameterWithManager
{
/**
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: 接收離線消息的級別
clientId: 客戶端id,需要特別指出的是這個(gè)id需要全局唯一,因?yàn)榉?wù)端是根據(jù)這個(gè)來區(qū)分不同的客戶端的,默認(rèn)情況下一個(gè)id登錄后,假如有另外的連接以這個(gè)id登錄,上一個(gè)連接會(huì)被踢下線, 我使用的設(shè)備UUID
*/
NSString *clientId = [UIDevice currentDevice].identifierForVendor.UUIDString;
self.sessionManager = [[MQTTSessionManager alloc] init];
[self.sessionManager connectTo:MQTTHOST
port:MQTTPORT
tls:false
keepalive:60 //心跳間隔不得大于120s
clean:true
auth:true
user:MQTTUSERNAME
pass:MQTTPASSWORD
will:false
willTopic:nil
willMsg:nil
willQos:0
willRetainFlag:false
withClientId:clientId];
self.sessionManager.delegate = self;
// 添加監(jiān)聽狀態(tài)觀察者
[self.sessionManager addObserver:self
forKeyPath:@"state"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:nil];
// 訂閱主題 NSDictionary類型,Object 為 QoS,key 為 Topic
self.sessionManager.subscriptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:MQTTQosLevelExactlyOnce] forKey:@"你要訂閱的主題(和后臺(tái)商量好)"];
}
監(jiān)聽連接狀態(tài)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)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ù)據(jù)
// 實(shí)現(xiàn)MQTTSessionManagerDelegate代理方法,處理數(shù)據(jù)。
- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained
{
NSLog(@"主題:%@",topic);
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSData * newData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:newData options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"數(shù)據(jù):%@",jsonDict);
}
最后不要忘記移除觀察者, 否則程序會(huì)崩潰
[self.sessionManager removeObserver:self forKeyPath:@"state"];