MQTT 协议(三):实战篇

作者: 小橘爷 | 来源:发表于2016-03-12 15:47 被阅读16833次

    如果觉得我写的还不错,请关注我的新浪微博@小橘爷,最新文章即时推送~
    MQTT 协议(一):理论篇
    MQTT 协议(二):推送篇
    在进行了两篇博客的理论覆盖后,我们来写一个 MQTT 的 Demo,看看如何在 iOS 开发中使用这项技术。

    寻找框架

    在面向对象的开发中,框架是快速开发的利器。封装良好的框架可以有效地帮助我们避免直接接触协议底层的一些东西。

    于是我打开了 Github,搜索 MQTT,找到了 Stars 最多的一个用 Objective-C 封装的 MQTT 框架:MQTT-Client-Framework。接下来让我们一起来学习如何使用这个框架~

    导入框架

    如果你比较喜欢用 Cocoapods(在工作中大家应该都会使用这个的,对吧?),可以把以下的语句写入 Podfile:

    pod 'MQTTClient'
    

    然后 pod update,完成之后我们就可以开心的使用这个框架啦~

    使用框架

    第一步,自然是导入 MQTT-Client-Framework 框架的主头文件:

    #import <MQTTClient/MQTTClient.h>
    

    第二步,在 AppDelegate 的类扩展里声明一个 MQTTSession 类的属性:

    @property (nonatomic, strong) MQTTSession *mySession;
    

    第三步,在 AppDelegate 中初始化 mySession:

    首先,初始化一个 MQTTCFSocketTransport 对象,这个对象是用来记录 MQTT 协议中的一些属性,例如:host(服务器),port(端口)等。

    MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init]; // 初始化对象
    
    transport.host = @"localhost"; // 设置MQTT服务器的地址
    
    transport.port = 1883; // 设置MQTT服务器的端口(默认是1883,当然,你也可以和你的后台好基友协商~)
    
    self.mySession = [[MQTTSession alloc] init]; // 初始化MQTTSession对象
    
    self.mySession.transport = transport; // 给mySession对象设置基本信息
    
    self.mySession.delegate = self; // 设置mySession的代理为APPDelegate,同时不要忘记遵守协议~
    
    [self.mySession connectAndWaitTimeout:30]; // 设定超时时长,如果超时则认为是连接失败,如果设为0则是一直连接。
    

    订阅主题

    正如我们在第一篇博文所说的,MQTT协议是一个发布/订阅式的协议,所以在创建和连接完成后,我们就开始订阅主题。

    [self.mySession subscribeToTopic:@"example/#" atLevel:2 subscribeHandler:^(NSError *error, NSArray*gQoss) {//Topic则表示要订阅的主题,Level(qosLevel)表示消息等级。
        if (error) {
            NSLog(@"Subscription failed %@", error.localizedDescription);
        } else {
            NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss);
        }
    }];
    

    收到消息

    - (void)newMessage:(MQTTSession *)session data:(NSData*)data onTopic:(NSString*)topic qos:(MQTTQosLevel)qos retained:(BOOL)retained mid:(unsignedint)mid {
        // 这个是代理回调方法,接收到的数据可以在这里进行处理。
    }
    

    发布消息

    [self.mySession publishAndWaitData:data
                                onTopic:@"topic"
                                 retain:NO
                                    qos:MQTTQosLevelAtLeastOnce];
    

    其中,data 表示你要发送的数据,topic 表示你向哪个主题发送数据,retain 如果是 YES, 数据会被存储在服务器,直到下一条 retain 也为YES的数据传入就会复写,qos 则是三种消息的等级,这些在第一篇博客中已经讲过了。

    总结

    大体上的用法就是这些,通过这几步就可以基本实现 MQTT 的基础功能了,至于保持心跳和使用 MQTT 框架搭建一个轻量级的即时通讯系统的问题,就靠同学们去框架里研究啦~

    相关文章

      网友评论

      • 米夕路痕:不错,最近在用,服务端用的是rabbitmq,添加mqtt插件,可以推送给android web
      • 请叫我小白同学:[MQTTSession] mqttTransport didFailWithError Error Domain=kCFErrorDomainCFNetwork Code=1 "(null)" UserInfo={_kCFStreamErrorCodeKey=1, _kCFStreamErrorDomainKey=12},错误怎么决解?
      • HotRay:- (void)newMessage:(MQTTSession *)session data:(NSData*)data onTopic:(NSString*)topic qos:(MQTTQosLevel)qos retained:(BOOL)retained mid:(unsignedint)mid {

        这是收到服务器的消息吗?
      • 闲云悠鹤蝶恋舞:你好,请问一下,使用MQTTClient做推送时,当App进入到后台后,就收不到服务器发送的消息了,但是打印出来的结果是仍处于与服务器连接的状态,当App进入到前台时,就能够收到服务器的消息,有什么好的解决办法吗?
        小橘爷:@闲云悠鹤蝶恋舞 如果不能申请到权限那还是放弃这个需求吧,不然会被苹果爸爸打回原形的。
        闲云悠鹤蝶恋舞:@杨浩宇 因为苹果本身就只对一些特殊的应用,如音乐,定位等之类的应用才具有后台运行的权限的,我们普通的一些APP 一般都是后台假运行
        小橘爷:@闲云悠鹤蝶恋舞 这个情况可能是应用没有做后台保活吧,应当尝试下后台权限的操作。
      • 150a36e4845f:楼主 ,方便发个demo嘛? 961429020@qq.com 问一下 可以实现mqtt的ssl加密码
        小橘爷:@奈何流水 我的demo已经没了,而且我做的时候也没用到你说的那些功能,你可以问问评论区里的其他人看看。
      • FLYflower:你好,楼主。MQTT锁屏后再打开就会断开连接,怎么设置能让他解锁后自动连接上呢?
        小橘爷:@FLYflower 在生命周期方法里重连就好啦~
      • 番茄爱说冷笑话:你好,楼主。我想让MQTT一直保持一个长连接,在后台的时候也能接收到服务器的消息,该怎么设置呢?
        小橘爷:@番茄爱说冷笑话 那个你需要在后台保活,有一个方法是把你的长链接交给系统来管理,不过我也只是在starkoverflow上看到过,没来得及试~
      • 912aef2f5ffa:各位用mqttclient framework 开发的,知道这个库支持ipv6吗
      • Woody_芜笛:请问博主用MQTT用来推送,有实践过吗,效果如何?
      • Woody_芜笛:问个问题,要加上用户名以及密码呢,怎么加上?
        小橘爷:@Wendy永 做过这个的推送,不过完全是实验性质的,就是让应用后台保活,收到mqtt消息之后转化为本地推送。至于用户名和密码还真没弄过,毕竟只是玩玩~
      • 绛紫哟:假如程序进入后台之后,再次打开app,可以接收到关闭app这段时间未接收到的消息吗?
        绛紫哟:@杨浩宇 还有就是苹果推送必须经过APNS,但是MQTT并没有经过APNS,那么如何保证程序进去后台的时候,一直监听消息呢?
        绛紫哟:@听海_sweety 可以给我发个demo吗?万分感谢
        小橘爷:@听海_sweety 只要消息类型选择必须送达就是可以的~
      • 912aef2f5ffa:-(void)handleEvent:(MQTTSession *)session event:(MQTTSessionEvent)eventCode error:(NSError *)error{

        switch (eventCode) {
        case MQTTSessionEventConnected:

        NSLog(@"mqtt connect Succesed");

        break;
        case MQTTSessionEventConnectionError:
        NSLog(@"connect error %@",error.localizedDescription);
        connectTimes++;
        sleep(connectTimes*2);

        // [deviceSession connect];
        break;
        case MQTTSessionEventConnectionRefused:
        NSLog(@"mqtt connect refused");
        break;
        case MQTTSessionEventConnectionClosed:
        NSLog(@"connect Closed");
        break;
        case MQTTSessionEventProtocolError:
        NSLog(@"protocol Error");

        break;
        default:
        break;


        }
        }
        我mqtt连接后,一开始是显示连接成功的,但是下一秒就是连接关闭, connect closed,我是用上面的方法来判断当前mqtt的连接状态的,这个问题,有谁知道原因,帮忙解答一下
      • 喵小帅:楼主问下使用MQTT和后台进行连接时,需要用到P12证书或者是cer之类的文件么
        小橘爷:@喵小帅 并没有,不如你咨询下评论过的其他人,或者使用manager那个类来进行处理,会比较方便。
        喵小帅:@杨浩宇 请问遇到过Error Domain=MQTT Code=-8 "Server has closed connection without connack." 这个问题么。。照着方法来的就是连接失败
        小橘爷:@喵小帅 并不需要~
      • 42576831c86a:楼主,我一直连接不成功,怎么回事呢 ??connected关于连接结果的3个方法,一个都没走。。 代码:

        MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];//初始化对象
        transport.host = Broker;//设置MQTT服务器的地址
        transport.port = Prot;//设置MQTT服务器的端口(默认是1883,当然,你也可以和你的后台好基友协商~)

        self.mySession = [[MQTTSession alloc] init];//初始化MQTTSession对象
        self.mySession.userName = UserName;
        self.mySession.password = Password;
        self.mySession.clientId = ConsumerId;
        self.mySession.transport = transport;//给mySession对象设置基本信息
        self.mySession.delegate = self;//设置mySession的代理为APPDelegate,同时不要忘记遵守协议~
        [self.mySession connectAndWaitTimeout:30];//设定超时时长,如果超时则认为是连接失败,如果设为0则是一直连接。
        [self.mySession subscribeToTopic:@"robot_server" atLevel:2 subscribeHandler:^(NSError *error, NSArray*gQoss) {//Topic则表示要订阅的主题,Level(qosLevel)表示消息等级。
        if (error) {
        NSLog(@"Subscription failed %@", error.localizedDescription);
        } else {
        NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss);
        }
        }];

        小橘爷:@42576831c86a 这些我没遇见过⋯⋯要不试试写成单例吧。
        42576831c86a:@杨浩宇 我知道为什么错了, 我host 写成服务器地址了 ,不是写的主机地址。。但是又有新的问题。。连了几秒就断了 :sob:
        小橘爷:@42576831c86a 你@的那个大萌哥哥用的是manager那个类成功了,要不你也试试那个类吧。我也好久没弄这块了,都快忘光了⋯⋯
      • 记住你姓李:骚年 你这个写的 有点 太过简单了 你这个还有什么值得推荐的博客 或者技术贴之类的吗? 所有相关的信息都可以 , 我们要搞物联网 , 现在正在找资料 研究
        小橘爷:@鬼话连篇 :joy:其实就是不全而且没能在实战中派上用场,问问他们吧,他们应该做的差不离了~
        记住你姓李:@杨浩宇 sorry 我没仔细看 , 昨天才知道 MQTT 不明白 看你这方法写的这么些 还以为写的不全 我在跟下面的 咨询咨询 :grin::grin:
        小橘爷:@鬼话连篇 这个之前我也是只写了个demo玩⋯⋯不过我强烈建议你看下本文下的评论,他们都是在实际项目中用到了mqtt,并且已经成功啦。你可以咨询下他们~
      • 大萌哥哥:博主 在吗,第一步,[self.mySession connectAndWaitTimeout:30]; 怎么知道他是否连接成功呢?我在 - (void)session:(MQTTSession*)sender handleEvent:(MQTTSessionEvent)eventCode 这个回调方法里面打断点,没走。。。求解,在线等
        小橘爷:@大萌哥哥 恭喜~:+1:🏻
        大萌哥哥:我用了这个大神的MQTTSessionManager解决了这个问题,已经和后台联通了 :smiley:
        小橘爷:@大萌哥哥 可能是出现了错误或者是什么吧,你可以把协议里其他的代理方法实现下输出一句log看看。
      • 22de578f6550:为什么我按照你的方法建立链接,却一直链接不上呢?以下是我的代码(另外:为什么这种方式链接我这还是TCP,而不是WEBSOCKET的方式建链?):

        MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];//初始化对象
        transport.host = MQTT_Base_URL;//设置MQTT服务器的地址
        transport.port = MQTT_Base_PORT;//设置MQTT服务器的端口(默认是11883,当然,你也可以和你的后台好基友协商~)
        self.mqttSession = [[MQTTSession alloc] init];//初始化MQTTSession对象
        self.mqttSession.transport = transport;//给mqttSession对象设置基本信息
        [self.mqttSession setClientId:@"mtimestampId"];
        [self.mqttSession setKeepAliveInterval:60];
        [self.mqttSession setUserName:self.userModel.token];
        [self.mqttSession setPassword:self.userModel.uid];
        [self.mqttSession setCleanSessionFlag:true];
        self.mqttSession.delegate = self;//设置mqttSession的代理,同时不要忘记遵守协议~
        [self.mqttSession connectAndWaitTimeout:30];//设定超时时长,如果超时则认为是连接失败,如果设为0则是一直连接。
        小橘爷:@shmilyliang mqtt本身就是基于tcp协议的连接,所以就是tcp啦~
        小橘爷:@shmilyliang 我这博客里写的默认端口貌似是1883吧⋯⋯:sweat:
        22de578f6550:#define MQTT_Base_URL @"112.124.120.127"
        #define MQTT_Base_PORT 11883 // websocket
      • dcc7e0b17c02:PO主你好,我使用了这个框架,transport.host = @"localhost";但是会出现错误"mqttTransport didFailWithError Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused"",
        请问这个是什么原因
        小橘爷:@cescxu 不客气,加油!
        dcc7e0b17c02:@杨浩宇 非常感谢您的帮助.
        小橘爷:@cescxu host应该用你们的mqtt服务器地址而不是localhost字符串。

      本文标题:MQTT 协议(三):实战篇

      本文链接:https://www.haomeiwen.com/subject/edpxlttx.html