iOS mqtt & protobuf(三) 合体

protobuf&Mqtt

1.简单来说就是将Data扔mqtt,然后发送出去就行了!!!

成果展示

启动服务器

image.png

Demo演示

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 
#import 
#import "MQTTUserInfo.h"
#import "MqttMessageBody.pbobjc.h"

typedef NS_ENUM(NSInteger, MQTTConnectionCode) {
    MQTTConnectionCodeDidConnection
};

@protocol AVAMqttManagerDelegate 

/**
 @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 代理对象
 */
- (void)addDelegatesWithObject:(id)delegate;

/**
 @method removeDelegateObject:
 @abstrac 删除一个代理对象
 @discussion 传入一个代理对象
 @param delegate id 代理对象
 */
- (void)removeDelegateObject:(id)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;
    }
}

Demo路径:https://github.com/Avanlanching/MQTTDemo

你可能感兴趣的:(iOS mqtt & protobuf(三) 合体)