MQTT

摘要:
MQTT简介MQTT基于订户模型体系结构。如果客户端彼此通信,它们必须在同一个订阅主题下,也就是说,它们都订阅同一个主题。客户端之间没有直接通信。基于MQTT客户机框架的IOS客户机实现了对现有客户机的sdk分析,基本上分为两类:一类是从C类库(如Mosquitto)移植的,另一类是用objc或swift本地实现的。各种sdk的比较如下。我选择MQTT客户机。使用swift的学生可以使用CocoaMQTT。这个sdk的作者也是服务器emqtt实现的作者。名称类型编程语言代码PahoOriginalCOpen-Source.EclipserProjectIBM OriginalCCloseSource.IBMSDKMosquittoOriginalCOpen-Source.IclipserprojectMQTKitWrapperObjective-COpen-Source.GGithubMarquetteWrapperobjective-COpen-Source.GGitHubMoscapsuleWrapperSwiftOpen-Source.GithubMusqueteerWrapper Objective-CMQTT-ClientNativeObjective-Cpen-Source。GithubMQTTSDK NativeObjective CCocoaMQTTNativeSwiftOpen Sour可能存在的问题。Github如下:苹果禁止第三方网络库使用移动网络。

MQTT简介

mqtt基于订阅者模型架构,客户端如果互相通信,必须在同一订阅主题下,即都订阅了同一个topic,客户端之间是没办法直接通讯的。订阅模型显而易见的好处是群发消息的话只需要发布到topic,所有订阅了这个topic的客户端就可以接收到消息了。

发送消息必须发送到某个topic,重点说明的是不管客户端是否订阅了该topic都可以向topic发送了消息,还有如果客户端订阅了该主题,那么自己发送的消息也会接收到。

另外需要重点说明的是QoS,这个代表消息的传输方式,QoS说明如下:

  • 0代表“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
  • 1代表“至少一次”,确保消息到达,但消息重复可能会发生。
  • 2代表“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。 备注:由于服务端采用Mosca实现,Mosca目前只支持到QoS 1

简单说明下,如果发送的是临时的消息,例如给某topic所有在线的设备发送一条消息,丢失的话也无所谓,0就可以了(客户端登录的时候要指明支持的QoS级别,同时发送消息的时候也要指明这条消息支持的QoS级别),如果需要客户端保证能接收消息,需要指定QoS为1,如果同时需要加入客户端不在线也要能接收到消息,那么客户端登录的时候要指定session的有效性,接收离线消息需要指定服务端要保留客户端的session状态。

基于MQTT-Client-Framework的IOS客户端实现

现有客户端sdk分析,基本分为两大类:一类移植自C类库,如Mosquitto,一类是用objc或者swift原生实现。
各种sdk对比如下,我选用的是MQTT-Client,使用swift的同学可以使用CocoaMQTT,这个sdk的作者同时也是服务端实现emqtt的作者。

NameTypeProgramming LanguageCode
PahoOriginalCOpen-Source. Eclipse project
IBMOriginalCClose Source. IBM SDK
MosquittoOriginalCOpen-Source. Eclipse project
MQTTKitWrapper (Mosquitto)Objective-COpen-Source. Github
MarquetteWrapper (Mosquitto)Objective-COpen-Source. Github
MoscapsuleWrapper (Mosquitto)SwiftOpen-Source. Github
MusqueteerWrapper (Mosquitto)Objective-C
MQTT-ClientNativeObjective-COpen-Source. Github
MQTTSDKNativeObjective-C
CocoaMQTTNativeSwiftOpen-Source. Github

可能的问题如下所述,苹果禁止第三方网络库使用移动网络。

If you are trying to use MQTT for an iOS application I will highly recommend you to use a native (Objective-C/Swift) iOS library. Using C or wrapper libraries usually means you are using POSIX networking calls at some point. Apple forbids the use of third party networking libraries from using the mobile internet antenna. Thus if you use Paho or something similar, you can only use MQTT when you are connected to a WiFi network.
源引自https://github.com/relayr/apple-mqtt-example

集成步骤

MQTT-Client支持pod,方便快速集成到工程中。简单说下应用场景,app在每部安装的终端上会产生不同的业务数据,而业务数据需要在各终端app上都要看到,所以需要同步所有终端的业务数据。mqtt的消息传输都是通过topic进行的,topic需要创建,按照mqtt实现没有单独的创建topic的方法,topic是和订阅绑定的。也就是说只要订阅了一个topic,服务端首先判断是否有topic存在,如果存在的话把当前客户端加入到订阅列表中,如果不在的话就先创建一个topic,同时把自己添加到订阅列表中。

建立连接

如果app需要在多个页面传输数据建议使用单例模式,建立一个全局的连接,复用连接。因为每次连接到服务端也是很消耗资源的。建立连接的代码如下:

1
MQTTSessionManager *sessionManager = [[MQTTSessionManager alloc] init];
 [sessionManager connectTo:@“192.168.1.4” //服务器地址
                      port:1883  //服务端端口号
                       tls:false //是否使用tls协议,mosca是支持tls的,如果使用了要设置成true
                 keepalive:60    //心跳时间,单位秒,每隔固定时间发送心跳包
                     clean:false //session是否清除,这个需要注意,如果味false,代表保持登录,如果客户端离线了再次登录就可以接收到离线消息
                      auth:true //是否使用登录验证,和下面的user和pass参数组合使用
                      user:_userName //用户名
                      pass:_passwd //密码
                 willTopic:@""  //下面四个参数用来设置如果客户端离线发送给其它客户端消息,当前参数是哪个topic用来传输离线消息,这里的离线消息都指的是客户端掉线后发送的掉线消息
                      will:@"" //自定义的离线消息,约定好格式就可以了
                   willQos:0  //接收离线消息的级别
            willRetainFlag:false 
              withClientId:]; //客户端id,需要特别指出的是这个id需要全局唯一,因为服务端是根据这个来区分不同的客户端的,默认情况下一个id登录后,假如有另外的连接以这个id登录,上一个连接会被踢下线

订阅和发送消息

连接一旦建立以后就可以订阅topic和发送消息了,订阅和发送消息代码如下:

1
//订阅topic
sessionManager.subscriptions = [[NSMutableDictionary alloc] init];
[sessionManager.subscriptions setObject:[NSNumber numberWithInt:1]
                                                                     forKey:_topic];
//发送消息,返回值msgid大于0代表发送成功
UInt16 msgid = [sessionManager sendData:[msg dataUsingEncoding:NSUTF8StringEncoding] //要发送的消息体
                                                                          topic:topic  //要往哪个topic发送消息                                                                        
                                                                            qos:1 //消息级别
                                                                         retain:false];

接收消息

接收消息有委托实现,实现如下委托MQTTSessionManagerDelegate接收消息

1
- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained;

根据topic可以区分不同的消息

监控连接状态

注册一个观察者,判断state获取不同的连接状态

1
//注册观察者,记得在离开页面时移除观察者
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    [sessionManager addObserver:self
                    forKeyPath:@"state"
                       options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                       context:nil];
}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    switch (sessionManager.state) {
        case MQTTSessionManagerStateClosed: //连接已经关闭
            break;
        case MQTTSessionManagerStateClosing: //连接正在关闭
            break;
        case MQTTSessionManagerStateConnected: //已经连接
            break;
        case MQTTSessionManagerStateConnecting: //正在连接中
            break;
        case MQTTSessionManagerStateError: //异常
            break;
        case MQTTSessionManagerStateStarting: //开始连接
        default:
            break;
    }
}

mqtt协议本身支持断线重连,另外单独说明此sdk在app退出到后台后自动断开连接,当回到前台时会自动重新连接

转自:https://www.cnblogs.com/youyong/p/11388401.html

免责声明:文章转载自《MQTT》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇07_RHEL7配置yum源搜狗五笔输入法自定义短语使用及设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

转:利用JavaScript实现图片标注——SearchMapIdentityTask

功能:功能实现了现在网络流行的定位后在地图上画一个图标,点击图标后弹出消息框。 思路:根据查询条件获得一个点的地图坐标,然后转换为屏幕坐标,利用js脚本动态图片到相应位置。 效果图如下: 主要实现步骤: 1、SearchMapIdentity.cs,该类主要实现查询获取点的地图坐标,地图坐标转换为屏幕坐标的方法,点击小图标时的回发调用,代码如下 1us...

Disruptor与Netty实现百万级(十)

实体对象: import java.io.Serializable; public class TranslatorData implements Serializable { private static final long serialVersionUID = 8763561286199081881L; private St...

df,dh 命令

原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/df2f05c4-beb9-48b0-a5d8-5c0f5560c853 --------------------------------df ,du ------------...

分享几种Linux软件的安装方法

Linux软件安装由于不同的Linux分支,安装方法也互不相同,介绍几种常见的安装方法。 http://wenku.baidu.com/link?url=hrOBvu_P-joieXLZfbUjkyRXMHC_CgeAZWjTTtiKKZZhcmNBTILoH2he0TJ9GuhCr75ud4IDuZohhHjzK3B_YPhCkWJ30umXLzdJZG...

Linux远程目录挂载

原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/ad99ab1d-1040-45e0-aaf6-f5d69c247862 问题: 1、如何使A服务器的某个目录挂载到B服务器的某个目录下,使其达到B服务下的目录文件一旦变更,...

【工利其器】必会工具之(三)systrace篇(1)官网翻译

前言        Android 开发者官网中对systrace(Android System Trace)有专门的介绍,本篇文章作为systrace系列的开头,笔者先不做任何介绍,仅仅翻译一下官网的介绍。在后续的文章中再整理一份学习教程,以及笔者的实践经历。官网中对该工具的介绍文档路径为【https://developer.android.google...