iOS MQTT 使用详解

文章首次整理发布自个人博客:一之笔 -> iOS MQTT 使用详解

引言

之前我整理过关于RabbitMQ在iOS中的应用;这个RabbitMQ,是MQTT的一个消息中间件;除了这个中间件,还有其他支持MQTT的中间件,我们服务端在新的物联网项目上,采用了MQTT协议,就使用上而言,我个人觉得,MQTT使用起来更简单,更方便,虽然碰到了比较Low的问题,下面会说到;

为什么有这个文章--整理的过程就是技术沉淀的过程

  • 第一次接触MQTT的时候,是看到这个文章的,排版不怎么舒服;
  • 很久之后,看到自己写的代码,又忘了,又得查找。整理的过程就是技术沉淀的过程
  • 为了其他开发者,能够方便又舒服的看到,至于能不能搜到,就看你能不能突破”结界“了;

MQTT介绍

MQTT简介

MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议--来源百度百科

MQTT,主要提供了订阅/发布两种消息模式,更为简约、轻量,易于使用,特别适合于受限环境(带宽低、网络延迟高、网络通信不稳定)的消息分发,属于物联网(Internet of Thing)的一个标准传输协议。

MQTT特点

MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议,具有以下特点:

  • 使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合;

  • 对负载内容屏蔽的消息传输;

  • 使用 TCP/IP 提供网络连接;

  • 有三种消息发布服务质量(Qos):

    • “至多一次”(QoS==0),消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。

    • “至少一次”(QoS==1),确保消息到达,但消息重复可能会发生。

    • “只有一次”(QoS==2),确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量。

支持语言

Java ,Javascript, C/C++, Python, Ruby, Objective-C

MQTT使用

使用流程

客户端登录业务系统,然后启动MQTT连接,订阅各种主题消息,如果连接失败,需要在回调里处理,重连,MQTT有一个连接的状态 MQTTSessionStatus,回调可以监听到;

订阅成功后,如果有新的消息推过来,这时候,就需要解析,一般需要提前跟后台约定好,数据的格式,方便客户端这边解析;

大概的流程如下:

client-server流程

MQTT 安装

pod 'MQTTClient'

开始使用

导入头文件 #import<MQTTClient/MQTTClient.h>

为了方便调用MQTT服务,我们自定义一个类,暂且就叫做

MQTTManger:NSObject

主要用来管理MQ的开始连接,订阅主题,取消订阅,关闭连接等;

因为,如果你在需要的页面上订阅数据,会写很多session的创建,主题的订阅,不方便维护,管理;

以下是MQTTManger的接口部分 .h 文件

/** 订阅主题,设置某一个订阅主题的VC为代理 */
- (void)startSubcribeMessageWithDeviceTheme:(NSString *)deviceTheme delegate:(id<MQTTSessionDelegate>)delegate;
/** 取消订阅 */
- (void)unSubscribeMessageWithDeviceTheme:(NSString *)deviceTheme delegate:(id<MQTTSessionDelegate>)delegate;
/** 开始连接 */
- (void)startConnectServer;
/** 关闭连接 */
- (void)disConnectServer;

开始连接

  • 设置服务地址,端口号
  • 创建session,设置用户名,密码,心跳设置,clientID,消息服务质量(Qos)等;
  • 开始连接
  • 监听MQTT连接状态
- (void)startConnectServer {
    //设置服务地址,端口号
    MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
    transport.host = @"192.168.*.**";
    transport.port = 1883;
    //创建session,设置用户名,密码,clientID,消息服务质量(Qos)等;
    MQTTSession *session = [[MQTTSession alloc] init];
    session.clientId = @"iOS_3456345745686";
    session.transport = transport;
    session.delegate = self;
    session.userName = @"liluxin";
    session.password = @"123345";
    session.cleanSessionFlag = YES;
    session.willQoS = MQTTQosLevelAtMostOnce;
    self.session = session;
    [session connectAndWaitTimeout:1];
    [session addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionOld) context:nil];
    //开始连接
    [session connectWithConnectHandler:^(NSError *error) {
        DebugLog(@"错误的信息:%@",error);
        if (error) return;
        DebugLog(@"MQTT链接成功了");
    }];
}

实现代理方法,监听MQTT的状态

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    DebugLog(@"MQTT的状态:%@_____%@",self.session,change);
    if (self.session.status == MQTTSessionStatusDisconnecting||MQTTSessionEventConnectionError) {
    //重连即可
        [self.session connect];
    }
}

关闭连接

当用户退出登录的时候,需要将MQTT关闭,即就是将delegate置为nil,然后断开连接,最后设置会话为nil;

- (void)disConnectServer {
    self.session.delegate = nil;
    [self.session disconnect];
    self.session = nil;
}

订阅主题

消息主题的格式,一般服务端定义好:类似这样的

/notification/public/device/LUCY3002/DQ00000001

注意:消息订阅必须在主线程中,因为如果放在子线程,消息的回调收不到消息;

这个文章说到了,可以参考下:

- (void)startSubcribeMessageWithDeviceTheme:(NSString *)deviceTheme delegate:(id<MQTTSessionDelegate>)delegate {
    //这里会把订阅的VC设置为代理,这个定于的VC实现代理方法就可以收到推送的消息了
     self.session.delegate = delegate;
    if (self.session.status == MQTTSessionStatusConnected) {
        //订阅
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.session subscribeToTopic:deviceTheme atLevel:MQTTQosLevelAtMostOnce subscribeHandler:^(NSError *error, NSArray<NSNumber *> *gQoss) {
                    if (error) {
                        NSLog(@"订阅失败 %@", error.localizedDescription);
                    }
                    else {
                        NSLog(@"订阅成功 %@", gQoss);
                    }
                }];
            });
        });
    }
}

实现消息的监听代理方法,对收到的消息,进行json-->model,然后更新UI即可;

#pragma mark - MQTTSessionDelegate
- (void)newMessage:(MQTTSession *)session data:(NSData *)data onTopic:(NSString *)topic qos:(MQTTQosLevel)qos retained:(BOOL)retained mid:(unsigned int)mid {
    NSError *error;
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data
                                                        options:NSJSONReadingMutableContainers
                                                          error:&error];
    DebugLog(@"主题信息:%@ \n,收到的信息:%@",topic,dic);
}

取消订阅主题

当用户退出某一个页面的时候,我们就需要取消订阅,如果不取消订阅,当有新消息来得时候,用户还是可以收到的,没什么用,除非是全局的推送,要不然不取消就是浪费资源;

- (void)unSubscribeMessageWithDeviceTheme:(NSString *)deviceTheme delegate:(id<MQTTSessionDelegate>)delegate {
    if (self.session.status == MQTTSessionStatusConnected) {
        //取消订阅
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.session unsubscribeTopic:deviceTheme unsubscribeHandler:^(NSError *error) {
                    if (error) {
                        NSLog(@"取消订阅失败 %@", error.localizedDescription);
                    }
                    else {
                        NSLog(@"取消订阅成功");
                        
                    }
                }];
            });
        });
    }
}

MQTTManger,到这里就结束了,基本上,使用的话,就直接调用对应的方法,简单,方便;

自己测试MQTT数据推送

模拟软件

如果想要自己测试推送数据的话,有一个工具模拟软件,可以下发消息,这个东西,没有RabbitMQ的管理台方便

不过这个东西,可以测试MQTT各种不同的情况,比较方便,不需要依赖后台,自己就可以

  • 创建连接

Connecetions-> newConnecetions

image
  • 设置参数
    下面这个基本是自动生成的,不用管,唯一的就是需要设置,server URL,这个跟服务端同学要一下;


    image

设置用户名密码

image

然后打开连接,就可以发布模拟消息了

  • 发布模拟消息

看图操作,没有你不会的;

image

Java运行环境

上面提到的模拟软件,需要在 Mac 电脑安装 Java 环境,配置环境变量

MQTT遇到的坑

我遇到的就是,自己明明连接成功了,也订阅成功了,就是收不到自己模拟发送的消息,我就纳闷了

后来发现,是一个很小很小的问题,是自己模拟软件的 服务端地址写成本地的了,因为我之前在本地部署过MQTT的服务,我自己手机连接的地址跟模拟软件的不一样,所以,收不到消息是正常的;

一开始,我以为是消息的订阅在子线程中,反复确定了,就是在主线程订阅的;

本地部署MQTT服务

如果想在本地部署MQTT的服务,可以看这个百万级分布式开源物联网MQTT消息服务器

image

很简单的,启动好之后,就可以访问控制台地址:

http://127.0.0.1:18083,

默认用户: admin,密码:public

这个管理台,我觉得,没啥用,不能操作,不能模拟发消息,可能对服务端监控有用;

如果有遇到问题,欢迎留言;

结束了

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

推荐阅读更多精彩内容

  • 网络编程 1. 概论 建立连接:通过IP或者域名来连接两台设备,通过端口号找到对应的通信程序 通信协议:要传输的数...
    陵无山阅读 3,966评论 0 12
  • 一、简介 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是I...
    一笑倾城Tan阅读 14,430评论 0 4
  • 1 前言 年初做了一款Android TV 应用,用到了MQTT。主要实现的是类似一些景区利用大屏幕实时显示景点人...
    wildma阅读 74,859评论 51 173
  • 汸念橙应该算是一个暴力奶妈,110多级有一万四的修为,曾经伊斯科为了看她的治疗血量,特意让她施展了云梦轻功江月流芳...
    殊旅三盏灯阅读 422评论 0 0
  • 【信息捕获】 关键词:水痘、《迟暮花开》、交谈 事件:玛雅生病了,是水痘。店员拿错了书。AJ看着真《迟暮花开》,决...
    韦泉宏阅读 111评论 0 2