protobuf&Mqtt
1.簡(jiǎn)單來(lái)說(shuō)就是將Data扔mqtt诗芜,然后發(fā)送出去就行了!!!
成果展示
啟動(dòng)服務(wù)器
image.png
Demo演示
mqttGIF.gif
具體代碼
CocoaPods導(dǎo)入需要的SDK
1.Protobuf是protobuf的依賴庫(kù)
2.MQTTClient是一個(gè)開源的Mqtt庫(kù)彼妻,包括鏈接噪漾,訂閱,發(fā)布消息馏慨,接收消息等等(只要站在巨人肩膀上開發(fā)就好了展东,除非你是研發(fā)型的公司寄雀,需要自己去研發(fā)一套協(xié)議或者一套新的框架)。
pod 'Protobuf'
pod 'MQTTClient'
3.創(chuàng)建一個(gè)通訊管理類(管理鏈接奶稠,中斷鏈接俯艰,接收和發(fā)送消息)
注意:這里僅作為展示,不做過(guò)多的處理锌订,需要做成一個(gè)完整的項(xiàng)目還需要更多的東西
//
// MqttManager.h
// MQTTDemo
//
// Created by Avalanching on 2019/3/27.
// Copyright ? 2019 Avalanching. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MQTTClient/MQTTClient.h>
#import "MQTTUserInfo.h"
#import "MqttMessageBody.pbobjc.h"
typedef NS_ENUM(NSInteger, MQTTConnectionCode) {
MQTTConnectionCodeDidConnection
};
@protocol AVAMqttManagerDelegate <NSObject>
/**
@method sendMessageCallBackWithBool:message:
@abstrac 發(fā)送回調(diào)
@discussion 回調(diào)結(jié)果是否發(fā)送成功了
@param flag 發(fā)送結(jié)果
@param body 發(fā)送的信息
*/
- (void)sendMessageCallBackWithBool:(BOOL)flag message:(MqttMessageBody *)body;
/**
@method newMessageArrival:
@abstrac 收到新的信息
@discussion 收到信息的回調(diào)
@param message 發(fā)送的信息
*/
- (void)newMessageArrival:(MqttMessageBody *)message;
@end
@interface MqttManager : NSObject
// 登陸信息
@property (nonatomic, strong, readonly) MQTTUserInfo * userinfo;
// 終端連接回調(diào)
@property (nonatomic, copy, readonly) BOOL (^interruptblock)(MQTTConnectionCode code, NSString *msg);
/**
@method shareManager
@abstrac 獲取一個(gè)管理者單例對(duì)象
@discussion 用來(lái)管理MQTT的綁定竹握,訂閱,鏈接辆飘,中斷啦辐,接收,發(fā)送
@result MqttManager / NULL (instancetype 僅返回值蜈项,告訴編譯器不報(bào)異常)
*/
+ (instancetype)shareManager;
/**
@method loginWithMQTTUserInfo:
@abstrac 用戶登陸MQTT服務(wù)器
@discussion 必須登陸以后才可以登陸
@param userinfo block
*/
- (void)loginWithMQTTUserInfo:(MQTTUserInfo *)userinfo complete:(BOOL(^)(MQTTConnectionCode code, NSString *msg))block;
/**
@method addSubscriptionWithTheme:
@abstrac 訂閱主題
@discussion 默認(rèn)為@"$SYS/IM"
@param theme NSString *
*/
- (BOOL)addSubscriptionWithTheme:(NSString *)theme;
/**
@method disConnection
@abstrac 中斷鏈接
*/
- (void)disConnection;
/**
@method sendMessageWithData:
@abstrac 發(fā)送消息
@param data NSString
*/
- (void)sendMessageWithData:(NSData *)data;
/**
@method isSendWithMessageBody:
@abstrac 判斷是不是發(fā)送者
@discussion 傳入一個(gè)消息對(duì)象
@param body MqttMessageBody*
@result BOOL (NO 接收者/YES 發(fā)送者)
*/
- (BOOL)isSendWithMessageBody:(MqttMessageBody *)body;
/**
@method addDelegatesWithObject:
@abstrac 添加一個(gè)代理對(duì)象
@discussion 傳入一個(gè)代理對(duì)象
@param delegate id<AVAMqttManagerDelegate> 代理對(duì)象
*/
- (void)addDelegatesWithObject:(id<AVAMqttManagerDelegate>)delegate;
/**
@method removeDelegateObject:
@abstrac 刪除一個(gè)代理對(duì)象
@discussion 傳入一個(gè)代理對(duì)象
@param delegate id<AVAMqttManagerDelegate> 代理對(duì)象
*/
- (void)removeDelegateObject:(id<AVAMqttManagerDelegate>)delegate;
@end
/** 登陸方法
* - (void)loginWithMQTTUserInfo:(MQTTUserInfo *)userinfo
* complete:(BOOL(^)(MQTTConnectionCode code, NSString *msg))block;
*/
在使用MQTTClient:
1.需要?jiǎng)?chuàng)建一個(gè)MQTTSession對(duì)象芹关,這是管理鏈接的上下文,控制鏈接紧卒,中斷充边,發(fā)送,消息,訂閱和驗(yàn)證等等浇冰。
MQTTSession是MQTTClient的core類的上層封裝贬媒,相當(dāng)于一個(gè)外部接口類,作者給其定義了多種方法肘习。
2.設(shè)置一個(gè)MQTTSession的Delegate际乘,用來(lái)處理鏈接相關(guān)的回調(diào)。
3.定義自己的通訊格式漂佩,上一章舉例了一個(gè)MessageBody對(duì)象(正常開發(fā)需要更多字段去標(biāo)識(shí)一條消息)
注意
1.MQTTSession提供了兩類型的構(gòu)建方法
a.常規(guī)方法
+ (id)alloc;
- (id)init;
b.類別中添加的方法
- (MQTTSession *)initWithClientId:(NSString *)clientId
userName:(NSString *)userName
password:(NSString *)password
keepAlive:(UInt16)keepAliveInterval
connectMessage:(MQTTMessage *)theConnectMessage
cleanSession:(BOOL)cleanSessionFlag
will:(BOOL)willFlag
willTopic:(NSString *)willTopic
willMsg:(NSData *)willMsg
willQoS:(MQTTQosLevel)willQoS
willRetainFlag:(BOOL)willRetainFlag
protocolLevel:(UInt8)protocolLevel
queue:(dispatch_queue_t)queue
securityPolicy:(MQTTSSLSecurityPolicy *) securityPolicy
certificates:(NSArray *)certificates;
雖然作者很貼心對(duì)參數(shù)進(jìn)行了解釋脖含,但我還是要在說(shuō)一下,避免篇幅過(guò)短成了水文
ClientId:客戶機(jī)標(biāo)識(shí)符向服務(wù)器標(biāo)識(shí)客戶機(jī)投蝉。如果為零养葵,則生成隨機(jī)的clientID
userName:用于身份驗(yàn)證的用戶名(或ID)的nsstring對(duì)象〈窭拢可能是零关拒。
password:用戶密碼的nsstring對(duì)象。如果用戶名為零庸娱,密碼也必須為零着绊。
keepAlive:是以秒為單位的時(shí)間間隔。mqttclient確保發(fā)送的控制包之間的間隔不超過(guò)keep-alive值熟尉。在沒有發(fā)送任何其他控制包的情況下归露,客戶機(jī)發(fā)送一個(gè)pingreq包,設(shè)置心跳間隔不得大于120s
connectMessage:鏈接發(fā)送的消息
cleanSession:指定服務(wù)器是否應(yīng)放棄以前的會(huì)話信息斤儿。
will:will標(biāo)志設(shè)置為yes剧包,則表示當(dāng)服務(wù)器檢測(cè)到客戶機(jī)由于任何原因(而非客戶機(jī)主動(dòng)斷開數(shù)據(jù)包)斷開連接時(shí),服務(wù)器必須發(fā)布will消息往果。異常退出
willTopic:如果上一項(xiàng)will標(biāo)志設(shè)置為yes玄捕,will主題是一個(gè)字符串,否則為nil棚放。
willMsg:如果will標(biāo)志設(shè)置為yes枚粘,則必須指定will消息,否則為nil飘蚯。
willQoS:指定發(fā)布will消息時(shí)要使用的qos級(jí)別馍迄。如果will標(biāo)志設(shè)置為no,那么will qos必須設(shè)置為0局骤。
willRetainFlag:指示服務(wù)器是否應(yīng)使用retainFlag發(fā)布will消息攀圈。如果will標(biāo)志設(shè)置為no,則will retain標(biāo)志必須設(shè)置為no峦甩。如果will標(biāo)志設(shè)置為yes:如果will retain設(shè)置為no赘来,服務(wù)器必須將will消息發(fā)布為非保留發(fā)布[mqtt-3.1.2-14]现喳。如果will retain設(shè)置為yes,服務(wù)器必須將will消息發(fā)布為保留發(fā)布[mqtt-3.1.2-15]犬辰。
protocolLevel:指定要使用的協(xié)議嗦篱。協(xié)議版本3.1.1的協(xié)議級(jí)別字段的值為4。版本3.1的值為3幌缝。
queue:安排流的隊(duì)列進(jìn)行排隊(duì)
securityPolicy:安全策略用于評(píng)估安全連接的服務(wù)器信任的安全策略灸促。
certificates:提供的描述回復(fù)需要客戶端證書的服務(wù)器的身份證書。
我采用的創(chuàng)建方式
// MQTT配置類涵卵,設(shè)置訪問地址和端口號(hào)
// MQTTCFSocketTransport 安全驗(yàn)證管理
MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
transport.host = HOST;
transport.port = PORT;
self.session = [[MQTTSession alloc] init];
self.session.transport = transport;
self.session.delegate = self;
// 設(shè)置超時(shí)
[self.session setDupTimeout:30];
// 設(shè)置賬號(hào)密碼
[self.session setUserName:userinfo.username];
[self.session setPassword:userinfo.password];
[self.session subscribeToTopic:DefaultsTheme atLevel:MQTTQosLevelAtMostOnce];
驗(yàn)證管理
- (MQTTSSLSecurityPolicy *)customSecurityPolicy {
MQTTSSLSecurityPolicy *securityPolicy = [MQTTSSLSecurityPolicy policyWithPinningMode:MQTTSSLPinningModeNone];
// 是否使用驗(yàn)證
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesCertificateChain = YES;
securityPolicy.validatesDomainName = NO;
// 需要證書請(qǐng)?jiān)O(shè)置這個(gè)
// securityPolicy.pinnedCertificates
return securityPolicy;
}
如何查看狀態(tài)
這里MQTTClient很貼心為我們提供了很多回調(diào)浴栽,包括鏈接狀態(tài)的回調(diào)
/** for mqttio-OBJC backward compatibility
@param session the MQTTSession reporting the event
@param eventCode the code of the event
*/
- (void)session:(MQTTSession*)session handleEvent:(MQTTSessionEvent)eventCode;
/** gets called when a connection has been successfully established
@param session the MQTTSession reporting the connect
*/
- (void)connected:(MQTTSession *)session;
/** gets called when a connection has been successfully established
@param session the MQTTSession reporting the connect
@param sessionPresent represents the Session Present flag sent by the broker
*/
- (void)connected:(MQTTSession *)session sessionPresent:(BOOL)sessionPresent;
/** gets called when a connection has been refused
@param session the MQTTSession reporting the refusal
@param error an optional additional error object with additional information
*/
- (void)connectionRefused:(MQTTSession *)session error:(NSError *)error;
/** gets called when a connection has been closed
@param session the MQTTSession reporting the close
*/
- (void)connectionClosed:(MQTTSession *)session;
/** gets called when a connection error happened
@param session the MQTTSession reporting the connect error
@param error an optional additional error object with additional information
*/
- (void)connectionError:(MQTTSession *)session error:(NSError *)error;
這里為了快速用了KVC,去觀察了“status”屬性
// 添加監(jiān)聽狀態(tài)觀察者
[self.session addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
// 監(jiān)聽當(dāng)前連接狀態(tài)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
MQTTSessionStatus eventCode = self.session.status;
switch (eventCode) {
case MQTTSessionStatusCreated:
NSLog(@"%s\n創(chuàng)建鏈接:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusConnecting:
NSLog(@"%s\n鏈接中:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusConnected:
NSLog(@"%s\n已經(jīng)鏈接:%ld", __func__, (long)eventCode);
if (_interruptblock) {
self.interruptblock(MQTTConnectionCodeDidConnection, @"已經(jīng)鏈接了");
}
break;
case MQTTSessionStatusDisconnecting:
NSLog(@"%s\n正在斷開鏈接:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusClosed:
NSLog(@"%s\n關(guān)閉鏈接:%ld", __func__, (long)eventCode);
if (self.isClose) {
return;
} else {
[self.session connect];
}
default:
NSLog(@"%s\n鏈接錯(cuò)誤:%ld", __func__, (long)eventCode);
break;
}
}