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 <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;
    }
}

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容