历经三天的寻找和尝试,终于完成了一个任务,任务要求的服务器访问用WebSocket的URL格式的,而访问结束后要进行订阅和消息发送,这更多出现在MQTT协议的框架里,例如这个文章

https://www.jianshu.com/p/80ea4507ca74   《iOS MQTT----MQTTClient实战-看这篇的就够了》。但是这个文章的框架访问示例代码的host和端口port设置的方式如下:

-(void)loginMQTT{/*设置ip和端口号*/self.transport.host=_ip;self.transport.port=_port;/*设置MQTT账号和密码*/self.mqttSession.transport=self.transport;//给MQTTSession对象设置基本信息self.mqttSession.delegate=self;//设置代理[self.mqttSession setUserName:_userName];[self.mqttSession setPassword:_password];//会话链接并设置超时时间[self.mqttSession connectAndWaitTimeout:5];
}

该方式的host格式严格是“xxx.xxx.xx.xx”,如果格式错误,会直接访问报错,域名解析错误。报错信息如下:

2021-05-27 09:49:58.630527+0800 Intelligent_fire_protection[28024:9675835] Error Domain=kCFErrorDomainCFNetwork Code=2 "(null)" UserInfo={_kCFStreamErrorDomainKey=12, _kCFStreamErrorCodeKey=8, kCFGetAddrInfoFailureKey=8}

有时也会返回404,报错信息如下

Error Domain=SRWebSocketErrorDomain Code=2132 "received bad response code from server 404" UserInfo={NSLocalizedDescription=received bad response code from server 404, HTTPResponseStatusCode=404}

如果格式包含了path,例如“ws://xxxx/xxxx.xx.xx/mqtt”,需要将    self.transport.host=_ip;和self.transport.port=_port;删去,改成self.transport.url=“ws://xxxx/xxxx.xx.xx/mqtt”。

实现效果我没具体实践,应该不会有问题,起初我没发现这个url属性,host地址又被框架定死没办法和后台统一,访问又一直失败,于是我换了一个网上的demo,在另一个demo里发现了url属性,并完成了我的需求,后来回头查看这个框架的时候,发现也有url属性。爬坑了。

接下来我简单介绍一下我应用的这个框架:

该框架引用来自:https://blog.csdn.net/sinat_23907467/article/details/84840699,《iOS MQTT 简单使用流程》

配置MQTT。 MQTTClient 配置更多 是可持续更新,可配置 SSL


pod 'MQTTClient'
pod 'MQTTClient/MinL'
pod 'MQTTClient/ManagerL'
pod 'MQTTClient/WebsocketL'

.h文件中添加文件头和MQTTsession变量


#import <MQTTClient.h>
#import <MQTTWebsocketTransport.h>
#define WEAKSELF   __typeof(&*self) __weak weakSelf = self;@property (nonatomic, strong) MQTTSession *mySession;

.m文件中添加协议<MQTTSessionDelegate,MQTTSessionManagerDelegate>,定义相应的变量,本文后续代码都在改.m文件中添加

@property(nonatomic,strong)NSString *server_ip;
@property(nonatomic,strong)NSString *userName;
@property(nonatomic,strong)NSString *passWord;
@property(nonatomic,strong)NSArray *topics;

文章中用到了下面的代码,但我在应用时候链接服务器报错了,我便把这部分代码注释掉了,实际上这部分代码只是避免持续等待连接卡死的情况,当连接时间超过某一个时间长度就强制断开申请连接。后文中我另加了一行代码实现这个功能。

        MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];transport.host = @"localhost";transport.port = 1883;MQTTSession *session = [[MQTTSession alloc] init];session.transport = transport;session.delegate = self;[session connectAndWaitTimeout:30];

WebSocket的初始化和链接代码:

引用的文章中用的是host和port,但这个不符合web的地址格式,往往web会有一个path路径,所以访问会报错,错误代码是5,MQTTSessionEventConnectionClosedByBroker。所以还需要在代码中添加一行transport.path=@"ws";或者将post和port两行注释掉,直接手动输入一个url 即 NSURL *url=[NSURL URLWithString:_server_ip];  transport.url=url;   其中_server_ip的格式为“ws://xxxx.xxxx.xx.xx/ws”

另外,上文中我注释掉的代码在此处实现了,即  [session connectAndWaitTimeout:10];

引用的文章中有个 [self reconnect];代码,实际是重新连接功能,实际使用时候文章没提供,已经没有这个函数了,所以我用的[self.mySession connect];代替。

    WEAKSELF
//    NSString *myId=[NSString stringWithFormat:@"%d",arc4random()%10000];NSString *clientID =[NSString stringWithFormat:@"%@|iOS|%@",[[NSBundle mainBundle] bundleIdentifier],[UIDevice currentDevice].identifierForVendor.UUIDString];;MQTTWebsocketTransport *transport = [[MQTTWebsocketTransport alloc] init];
//    transport.host = [NSString stringWithFormat:@"%@",server_ip];
//    transport.port =  9999;  // 端口号NSURL *url=[NSURL URLWithString:_server_ip];transport.url=url;
//    transport.path=@"ws";transport.tls = YES; //  根据需要配置  YES 开起 SSL 验证 此处为单向验证 双向验证 根据SDK 提供方法直接添加MQTTSession *session = [[MQTTSession alloc] init];NSString *linkUserName = _userName;NSString *linkPassWord = _passWord;[session setUserName:linkUserName];[session setClientId:clientID];[session setPassword:linkPassWord];[session setKeepAliveInterval:5];session.transport = transport;session.delegate = self;[session connectAndWaitTimeout:10];self.mySession = session;[self.mySession connect];//self reconnect[self.mySession addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; //添加事件监听

WebSocket 监听,响应事件:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {switch (self.mySession.status) {case MQTTSessionManagerStateClosed:NSLog(@"连接已经关闭");break;case MQTTSessionManagerStateClosing:NSLog(@"连接正在关闭");break;case MQTTSessionManagerStateConnected:NSLog(@"已经连接");break;case MQTTSessionManagerStateConnecting:NSLog(@"正在连接中");break;case MQTTSessionManagerStateError: {//            NSString *errorCode = self.mySession.lastErrorCode.localizedDescription;NSString *errorCode = self.mySession.description;NSLog(@"连接异常 ----- %@",errorCode);}break;case MQTTSessionManagerStateStarting:NSLog(@"开始连接");break;default:break;}
}

session Delegate 协议

连接 返回状态

根据我的项目需求,我直接在订阅成功后直接对topic进行了订阅,即代码中for循环,读者可以自行更改订阅逻辑。

-(void)handleEvent:(MQTTSession *)session event:(MQTTSessionEvent)eventCode error:(NSError *)error{if (eventCode == MQTTSessionEventConnected) {NSLog(@"链接MQTT 成功");// 方法 封装 可外部调用for (NSString *topic in _topics) {[session subscribeToTopic:topic atLevel:2 subscribeHandler:^(NSError *error, NSArray<NSNumber *> *gQoss){if (error) {NSLog(@"Subscription failed %@", error.localizedDescription);} else {NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss);//                [self send];}}];}// this is part of the block API}else if (eventCode == MQTTSessionEventConnectionRefused) {NSLog(@"MQTT拒绝链接");}else if (eventCode == MQTTSessionEventConnectionClosed){NSLog(@"MQTT链接关闭");}else if (eventCode == MQTTSessionEventConnectionError){NSLog(@"MQTT 链接错误");}else if (eventCode == MQTTSessionEventProtocolError){NSLog(@"MQTT 不可接受的协议");}else{//MQTTSessionEventConnectionClosedByBrokerNSLog(@"MQTT链接 其他错误");}if (error) {NSLog(@"链接报错  -- %@",error);}
}

收到来自服务器的信息,并对改信息进行相应处理

-(void)newMessage:(MQTTSession *)session data:(NSData *)data onTopic:(NSString *)topic qos:(MQTTQosLevel)qos retained:(BOOL)retained mid:(unsigned int)mid
{NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
//    NSLog(@"EasyMqttService mqtt connect success  %@",dic);// 做相对应的操作
}

取消订阅,断开与服务器的链接:

-(void)closeMQTTClient{[self.mySession disconnect];[self.mySession unsubscribeTopics:@[@"已经订阅的主题"] unsubscribeHandler:^(NSError *error) {if (error) {NSLog(@"取消订阅失败");}else{NSLog(@"取消订阅成功");}}];
}

以下内容是我封装了该框架,并留了三个方法用于链接,发送数据和断开连接。读者自行在.h文件中添加对应的方法:

-(void)connectServer:(NSString *)urlString userName:(NSString *)userName passWord:(NSString *)passWord topic:(NSArray *)topics{_server_ip=urlString;_userName=userName;_passWord=passWord;_topics=topics;[self websocket];}
-(void)disConnectServer{[_mySession closeAndWait:1];self.mySession.delegate=nil;//代理_mySession=nil;
//    _transport=nil;//连接服务器属性_server_ip=nil;//服务器ip地址
//    _port=0;//服务器ip地址_userName=nil;//用户名_passWord=nil;//密码
//    _topic=nil;//单个主题订阅_topics=nil;//多个主题订阅
}
-(void)sendMassage:(NSData *)msg topic:(NSString *)topic{[self.mySession publishData:msg onTopic:topic retain:NO qos:MQTTQosLevelExactlyOnce publishHandler:^(NSError *error) {if (error) {NSLog(@"发送失败 - %@",error);}else{NSLog(@"发送成功");}}];
}

iOS中MQTT和WS的简单混合使用相关推荐

  1. ios android md5加密,iOS中使用MD5加密

    在iOS中使用MD5加密较简单,需要引入头文件CommonCrypto/CommonDigest.h,我们单独新建一个用于MD5加密的类Encryption,此类继承NSObject. Encrypt ...

  2. iOS中SDK的简单封装与使用

    一.功能总述 在博客开始的第一部分,我们先来看一下我们最终要实现的效果.下图中所表述的就是我们今天博客中要做的事情,下方的App One和App Two都植入了我们将要封装的LoginSDK, 两个A ...

  3. 1、OPenGL ES - 简介、iOS中GLKit简单应用

    OPenGL ES -  简介.iOS中GLKit简单应用 一.OPenGL ES 1.简介: OpenGL ES 是以手持和嵌入式为目标的高级的3D图形应用程序编程接口(API),OpenGL ES ...

  4. iphone smtp服务器没有响应,电子邮件卡在iPhone或iPad上的发件箱?如何修复iOS中的未发送邮件 | MOS86...

    您曾经在iOS中发送电子邮件,只能将信息卡在iPhone,iPad或iPod touch的邮件应用发件箱中?你知道这是什么时候发生的,因为在iOS的Mail应用程序的底部,状态栏在iOS中显示1个未发 ...

  5. iOS中几种数据持久化方案总结

    概论 所谓的持久化,就是将数据保存到硬盘中,使得在应用程序或机器重启后可以继续访问之前保存的数据.在iOS开发中,有很多数据持久化的方案,接下来我将尝试着介绍一下5种方案: plist文件(属性列表) ...

  6. iOS中关于NSTimer使用知多少

    看到这个标题,你可能会想NSTimer不就是计时器吗,谁不会用,不就是一个能够定时的完成任务的东西吗? 我想说你知道NSTimer会retain你添加调用方法的对象吗?你知道NSTimer是要加到ru ...

  7. 在iOS中使用tableView

    为什么80%的码农都做不了架构师?>>>    UITableView是iOS中最常用的控件了,所以使用起来也很简单. ViewContoller.h 文件 (继承UITableVi ...

  8. 关于ios中编译ffmpeg0.9.2库

    很多朋友在问如何在ios中编译ffmpeg库,虽说网上的教程很多,但是大部分都说按其操作,最后编译总是不成功,正好我最近的项目要用到ffmpeg,所以就再次编译了,同时在这里记下,方便需要参考的朋友. ...

  9. iOS 中KVC、KVO、NSNotification、delegate 总结及区别

    iOS 中KVC.KVO.NSNotification.delegate 总结及区别 1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属 ...

最新文章

  1. 【特征工程】与【表示学习】
  2. 设计模式(中介者模式)
  3. oracle数据库中表被锁,Oracle数据库表被锁问题处理
  4. storm的流分组策略
  5. Go语言vscode环境配置
  6. linux free 命令中buffers、cached以及-/+ buffers/cache解析
  7. 服务器文件同步本站,服务器文件同步
  8. Jmeter --- Http Cookie Manager
  9. 系统性谈谈软件可靠性——第5讲:软件测试及常见测试用例设计方法
  10. 计算机的科学导论pdf,教材计算机科学导论.PDF
  11. 论文参考文献正确插入方法 (一)
  12. ifcfg-eth0配置详解
  13. 徐思201771010132《面向对象程序设计(java)》第十六周学习总结
  14. 儿童过敏性鼻炎的最佳治疗方法
  15. keras中sample_weight的使用
  16. 【CSDN|每日一练】小艺的英文名
  17. Unknown host 'dl.google.com'. You may need to adjust the proxy settings in Gradle.
  18. 海康IPC+ffmpeg+nginx+ckplayer实现网页实时预览监控视频
  19. web调用摄像头拍照并上传到服务器
  20. Java throw和throws关键字的使用及区别

热门文章

  1. C语言入门第二章-分支循环语句
  2. 趣学python编程答案_《趣学Python编程》习题总结
  3. 东京铁塔Mac高清壁纸
  4. 甜美动漫mac高清壁纸分享
  5. 入侵AI Medusa 的赛博之海,诚邀#光点2022
  6. Photoshop加边框脚本
  7. Design System Application - Chapter 1 网格系统 Grid System
  8. 数字图像处理(十一)白平衡算法
  9. RK3568—基于GM8775C的MIPI转双通道LVDS屏幕调试
  10. 视频专栏《软件测试工程师 必备 之 Jenkins / Linux / Git》基础视频