protobuf&Mqtt
1.简单来说就是将Data扔mqtt,然后发送出去就行了!!!
成果展示
启动服务器
image.pngDemo演示
mqttGIF.gif具体代码
CocoaPods导入需要的SDK
1.Protobuf是protobuf的依赖库
2.MQTTClient是一个开源的Mqtt库,包括链接,订阅,发布消息,接收消息等等(只要站在巨人肩膀上开发就好了,除非你是研发型的公司,需要自己去研发一套协议或者一套新的框架)。
pod 'Protobuf'
pod 'MQTTClient'
3.创建一个通讯管理类(管理链接,中断链接,接收和发送消息)
注意:这里仅作为展示,不做过多的处理,需要做成一个完整的项目还需要更多的东西
//
// 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 发送回调
@discussion 回调结果是否发送成功了
@param flag 发送结果
@param body 发送的信息
*/
- (void)sendMessageCallBackWithBool:(BOOL)flag message:(MqttMessageBody *)body;
/**
@method newMessageArrival:
@abstrac 收到新的信息
@discussion 收到信息的回调
@param message 发送的信息
*/
- (void)newMessageArrival:(MqttMessageBody *)message;
@end
@interface MqttManager : NSObject
// 登陆信息
@property (nonatomic, strong, readonly) MQTTUserInfo * userinfo;
// 终端连接回调
@property (nonatomic, copy, readonly) BOOL (^interruptblock)(MQTTConnectionCode code, NSString *msg);
/**
@method shareManager
@abstrac 获取一个管理者单例对象
@discussion 用来管理MQTT的绑定,订阅,链接,中断,接收,发送
@result MqttManager / NULL (instancetype 仅返回值,告诉编译器不报异常)
*/
+ (instancetype)shareManager;
/**
@method loginWithMQTTUserInfo:
@abstrac 用户登陆MQTT服务器
@discussion 必须登陆以后才可以登陆
@param userinfo block
*/
- (void)loginWithMQTTUserInfo:(MQTTUserInfo *)userinfo complete:(BOOL(^)(MQTTConnectionCode code, NSString *msg))block;
/**
@method addSubscriptionWithTheme:
@abstrac 订阅主题
@discussion 默认为@"$SYS/IM"
@param theme NSString *
*/
- (BOOL)addSubscriptionWithTheme:(NSString *)theme;
/**
@method disConnection
@abstrac 中断链接
*/
- (void)disConnection;
/**
@method sendMessageWithData:
@abstrac 发送消息
@param data NSString
*/
- (void)sendMessageWithData:(NSData *)data;
/**
@method isSendWithMessageBody:
@abstrac 判断是不是发送者
@discussion 传入一个消息对象
@param body MqttMessageBody*
@result BOOL (NO 接收者/YES 发送者)
*/
- (BOOL)isSendWithMessageBody:(MqttMessageBody *)body;
/**
@method addDelegatesWithObject:
@abstrac 添加一个代理对象
@discussion 传入一个代理对象
@param delegate id<AVAMqttManagerDelegate> 代理对象
*/
- (void)addDelegatesWithObject:(id<AVAMqttManagerDelegate>)delegate;
/**
@method removeDelegateObject:
@abstrac 删除一个代理对象
@discussion 传入一个代理对象
@param delegate id<AVAMqttManagerDelegate> 代理对象
*/
- (void)removeDelegateObject:(id<AVAMqttManagerDelegate>)delegate;
@end
/** 登陆方法
* - (void)loginWithMQTTUserInfo:(MQTTUserInfo *)userinfo
* complete:(BOOL(^)(MQTTConnectionCode code, NSString *msg))block;
*/
在使用MQTTClient:
1.需要创建一个MQTTSession对象,这是管理链接的上下文,控制链接,中断,发送,消息,订阅和验证等等。
MQTTSession是MQTTClient的core类的上层封装,相当于一个外部接口类,作者给其定义了多种方法。
2.设置一个MQTTSession的Delegate,用来处理链接相关的回调。
3.定义自己的通讯格式,上一章举例了一个MessageBody对象(正常开发需要更多字段去标识一条消息)
注意
1.MQTTSession提供了两类型的构建方法
a.常规方法
+ (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;
虽然作者很贴心对参数进行了解释,但我还是要在说一下,避免篇幅过短成了水文
ClientId:客户机标识符向服务器标识客户机。如果为零,则生成随机的clientID
userName:用于身份验证的用户名(或ID)的nsstring对象。可能是零。
password:用户密码的nsstring对象。如果用户名为零,密码也必须为零。
keepAlive:是以秒为单位的时间间隔。mqttclient确保发送的控制包之间的间隔不超过keep-alive值。在没有发送任何其他控制包的情况下,客户机发送一个pingreq包,设置心跳间隔不得大于120s
connectMessage:链接发送的消息
cleanSession:指定服务器是否应放弃以前的会话信息。
will:will标志设置为yes,则表示当服务器检测到客户机由于任何原因(而非客户机主动断开数据包)断开连接时,服务器必须发布will消息。异常退出
willTopic:如果上一项will标志设置为yes,will主题是一个字符串,否则为nil。
willMsg:如果will标志设置为yes,则必须指定will消息,否则为nil。
willQoS:指定发布will消息时要使用的qos级别。如果will标志设置为no,那么will qos必须设置为0。
willRetainFlag:指示服务器是否应使用retainFlag发布will消息。如果will标志设置为no,则will retain标志必须设置为no。如果will标志设置为yes:如果will retain设置为no,服务器必须将will消息发布为非保留发布[mqtt-3.1.2-14]。如果will retain设置为yes,服务器必须将will消息发布为保留发布[mqtt-3.1.2-15]。
protocolLevel:指定要使用的协议。协议版本3.1.1的协议级别字段的值为4。版本3.1的值为3。
queue:安排流的队列进行排队
securityPolicy:安全策略用于评估安全连接的服务器信任的安全策略。
certificates:提供的描述回复需要客户端证书的服务器的身份证书。
我采用的创建方式
// MQTT配置类,设置访问地址和端口号
// MQTTCFSocketTransport 安全验证管理
MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
transport.host = HOST;
transport.port = PORT;
self.session = [[MQTTSession alloc] init];
self.session.transport = transport;
self.session.delegate = self;
// 设置超时
[self.session setDupTimeout:30];
// 设置账号密码
[self.session setUserName:userinfo.username];
[self.session setPassword:userinfo.password];
[self.session subscribeToTopic:DefaultsTheme atLevel:MQTTQosLevelAtMostOnce];
验证管理
- (MQTTSSLSecurityPolicy *)customSecurityPolicy {
MQTTSSLSecurityPolicy *securityPolicy = [MQTTSSLSecurityPolicy policyWithPinningMode:MQTTSSLPinningModeNone];
// 是否使用验证
securityPolicy.allowInvalidCertificates = YES;
securityPolicy.validatesCertificateChain = YES;
securityPolicy.validatesDomainName = NO;
// 需要证书请设置这个
// securityPolicy.pinnedCertificates
return securityPolicy;
}
如何查看状态
这里MQTTClient很贴心为我们提供了很多回调,包括链接状态的回调
/** 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”属性
// 添加监听状态观察者
[self.session addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
// 监听当前连接状态
- (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创建链接:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusConnecting:
NSLog(@"%s\n链接中:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusConnected:
NSLog(@"%s\n已经链接:%ld", __func__, (long)eventCode);
if (_interruptblock) {
self.interruptblock(MQTTConnectionCodeDidConnection, @"已经链接了");
}
break;
case MQTTSessionStatusDisconnecting:
NSLog(@"%s\n正在断开链接:%ld", __func__, (long)eventCode);
break;
case MQTTSessionStatusClosed:
NSLog(@"%s\n关闭链接:%ld", __func__, (long)eventCode);
if (self.isClose) {
return;
} else {
[self.session connect];
}
default:
NSLog(@"%s\n链接错误:%ld", __func__, (long)eventCode);
break;
}
}
网友评论