文章目录

  • 1.集成第三方开源库 CocoaAsyncSocket
  • 2.对第三库进行二次封装
  • 3.用微信的Airkiss给机器人配网
  • 4.iOS13后无法获取wifi名的解决
  • 相关博客

1.集成第三方开源库 CocoaAsyncSocket

CocoaAsyncSocket

2.对第三库进行二次封装

RZSocketTools.h

//
//  RZSocketTools.h
//  UDPTest
//
//  Created by  on 17/3/8.
//  Copyright © 2017年 刘. All rights reserved.
//#import <Foundation/Foundation.h>#define AUTO_RECONNECT_NAME @"AUTO_RECONNECT_NAME"typedef void(^ConnectStateBlock)(BOOL connectState);
typedef void(^RBServersBlock)(NSMutableArray *servers);
typedef void(^RBServerMsgBlock)(NSDictionary * msgDic);
typedef void(^RBGetEMIdMsgBlock)(NSDictionary *msgDic);@interface RZSocketTools : NSObject@property (nonatomic,copy) ConnectStateBlock   connectStateBlock;           //链接状态更新
@property (nonatomic,copy) RBServersBlock       serverBlock;                //获取搜索到的设备
@property (nonatomic,copy) RBGetEMIdMsgBlock    getIdBlock;                 //获取到环信ID block
@property (nonatomic,copy) NSMutableArray       *serverArrs;                //UDP监听到的服务器数组
@property (nonatomic,assign)  BOOL              connectAuto;                //是否自动重连
@property (nonatomic,assign)  BOOL              connectState;               //机器人链接状态
@property (nonatomic,assign)  BOOL              udpReciveState;             //判断是否有接受到UDP,没有接受到 弹出AirKiss 网络链接框+ (instancetype)shareSocketTool;- (void)scanNearServers;                                                            //搜索周围机器人
- (void)close;
- (void)connectRobot:(NSString*)robotName;                                          //链接机器人
- (BOOL)sendMsgToRobot:(NSDictionary*)msgDic CallBack:(RBServerMsgBlock)msgBlock;          //发送信息给机器人
- (void)disConnectRobot;                                                                //断开机器人链接@end

RZSocketTools.m

//
//  RZSocketTools.m
//  UDPTest
//
//  Created by on 17/3/8.
//  Copyright © 2017年 . All rights reserved.
//#import "RZSocketTools.h"
#import "GCDAsyncUdpSocket.h"
#import "GCDAsyncSocket.h"
#import "common.h"
#import "Socket_Defines.h"#define UDP_PORT 30695
#define TCP_PORT 30690#define IOS_CLIENT @"X-ZERO-IOS"#define SERVER_NAME #define TCP_FIRST_TAG @"0"#define AUTO_CONNECT_MAX 6      //自动重连数据
#define AUTO_TIME_SPACE 5       //自动重连时间间隔
#define SEND_HEART_TIME_SPACE 13    //发送心跳包数据时间间隔 13
#define ACCEPT_HEART_TIME_SPACE 40   //未收到心跳包数据时间间隔  40@interface RZSocketTools()<GCDAsyncUdpSocketDelegate,GCDAsyncSocketDelegate>
{GCDAsyncUdpSocket       *asyncUdpSocket;        //UDPSocketGCDAsyncSocket           *asyncSocket;          //TCPSocketRBServerMsgBlock       msgReveiceBlock;                 //消息回调NSTimer                   *sendTimer;              //定时想服务器发送消息,保持服务器socket不断NSString                  *connectName;             //连接的设备名称NSDictionary                *currentPacketHead;
//    BOOL                      sendHeartFlag;            //发送心跳包数据标志量 SEND_HEART_TIME_SPACE后不发送NSTimer                     *noSendTimer;   //断开连接的轮训   60s未收到自动断开BOOL                      startAutoConnect;               //开机自动重连
}
@endstatic RZSocketTools *socketTool = nil;
@implementation RZSocketTools+ (instancetype)shareSocketTool
{static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{socketTool = [[super allocWithZone:NULL] init];[socketTool initSocket];});//lxaddlxif (!socketTool) {socketTool = [[super allocWithZone:NULL] init];[socketTool initSocket];}return socketTool;
}- (void)close{socketTool = nil;
}+ (id)allocWithZone:(struct _NSZone *)zone
{return [RZSocketTools shareSocketTool];
}- (id)copyWithZone:(struct _NSZone *)zone
{return  [RZSocketTools shareSocketTool];
}#pragma mark - InitSocket
- (void)initSocket
{_serverArrs = [NSMutableArray arrayWithCapacity:15];asyncUdpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];NSError *err = nil;[asyncUdpSocket enableBroadcast:YES error:&err];[asyncUdpSocket bindToPort:UDP_PORT error:&err];asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];_connectState = NO;//是否收到UDP_udpReciveState = NO;//自动连接//这句是控制启动APP后首次扫描时,自动连接最后一次连接的设备的startAutoConnect = YES;sendTimer = [NSTimer timerWithTimeInterval:SEND_HEART_TIME_SPACE target:self selector:@selector(sendHeartData) userInfo:nil repeats:YES];   //定义心跳轮询connectName = [NSString string];//lx开心跳包,自动重连存到沙盒的机器人[socketTool autoConnectTcp:[UserDataHelper getUserData:AUTO_RECONNECT_NAME]];                //设置自动重连}#pragma mark - ConnectTcp//扫描周围的设备
- (void)scanNearServers
{[_serverArrs removeAllObjects];[asyncUdpSocket receiveOnce:nil];}//根据机器名字来链接TCP
- (void)connectRobot:(NSString*)robotName
{NSMutableArray *arr = _serverArrs;for (NSDictionary *dic in _serverArrs) {if ([dic[@"name"] isEqualToString:robotName]){NSError *err;[asyncSocket disconnect];//收到消息后反馈给robotNSData *clientData = [IOS_CLIENT dataUsingEncoding:NSUTF8StringEncoding];[asyncUdpSocket sendData:clientData toHost:dic[@"ip"] port:UDP_PORT withTimeout:2 tag:1];[NSThread sleepForTimeInterval:0.8];BOOL flag = [asyncSocket connectToHost:dic[@"ip"] onPort:TCP_PORT error:&err];connectName = robotName;NSLog(@"链接TCP%d,%@",flag,err);break;}}
}//给rb发送指令并且回调
- (BOOL)sendMsgToRobot:(NSDictionary*)msgDic CallBack:(RBServerMsgBlock)msgBlock
{//    NSLog(@"给机器人发消息(未连接)%@",msgDic);if (!_connectState) {return NO;}NSLog(@"lxadd给机器人发的信息%@",msgDic);msgReveiceBlock = msgBlock;[socketTool sendMsgToRobot:msgDic];return YES;
}//断开TCP直接的链接
- (void)disConnectRobot
{NSLog(@"发断开连接");[asyncSocket disconnect];socketTool.connectAuto = NO;
}//自动重连
- (void)autoConnectTcp:(NSString*)robotName
{if (_connectAuto && ([robotName isEqualToString:[UserDataHelper getUserData:AUTO_RECONNECT_NAME]])) {//存到沙盒的机器人名字for (NSInteger i = 0; i < AUTO_CONNECT_MAX; i++) {NSTimeInterval autoTime = i * AUTO_TIME_SPACE + i*i;        //重连4次NSTimer *autoTimer = [NSTimer timerWithTimeInterval:autoTime target:self selector:@selector(sendAutoConnect:) userInfo:nil repeats:NO];   //定义心跳重连[[NSRunLoop mainRunLoop] addTimer:autoTimer forMode:NSRunLoopCommonModes];}}
}- (void)sendAutoConnect:(NSTimer*)timer
{// NSLog(@"自动重连的心跳包");if (_connectState) {[timer invalidate];return;}[socketTool connectRobot:connectName];
}#pragma mark - UDPDelegate
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(nullable id)filterContext
{//    NSLog(@"lxaddl--udpDidReceiveData");//这里需要把robot-name,IP地址 记录下来;NSString *robotName = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];[asyncUdpSocket receiveOnce:nil];if ([robotName hasPrefix:SERVER_NAME] && [GCDAsyncUdpSocket isIPv4Address:address]) {_udpReciveState = YES;if (![_serverArrs containsObject:@{@"name":robotName,@"ip":[GCDAsyncUdpSocket hostFromAddress:address]}]) {NSMutableArray *testArr = _serverArrs;NSDictionary *dict = @{@"name":robotName,@"ip":[GCDAsyncUdpSocket hostFromAddress:address]};[_serverArrs addObject:@{@"name":robotName,@"ip":[GCDAsyncUdpSocket hostFromAddress:address]}];
//            _serverArrs = [_serverArrs mutableCopy];if (socketTool.serverBlock) {dispatch_async(dispatch_get_main_queue(), ^{socketTool.serverBlock(_serverArrs);});}if ([robotName isEqualToString:[UserDataHelper getUserData:AUTO_RECONNECT_NAME]] && startAutoConnect) {     //开机自动连接
//                NSLog(@"开机自动连接");
//                NSString *str = [UserDataHelper getUserData:AUTO_RECONNECT_NAME];
//
//                [self connectRobot:[UserDataHelper getUserData:AUTO_RECONNECT_NAME]];}}}}- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{NSLog(@"消息已经发送出去 ,%ld",tag);
}- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error
{NSLog(@"消息并没有发送出去,请重试 ,%ld,err:%@",tag,error);
}- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error
{assert(@"UDP 无法连接");
}- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError  * _Nullable)error
{assert(@"UDP Socket 关闭");
}#pragma mark - TCPDelegate
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{NSLog(@"didAcceptNewSocket");
}//机器人连接成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{if (asyncSocket == nil) {asyncSocket = sock;}_connectAuto = NO;_connectState = YES;startAutoConnect = NO;if (socketTool.connectStateBlock) {dispatch_async(dispatch_get_main_queue(), ^{socketTool.connectStateBlock(_connectState);});}//把连到的机器人名字存进沙盒[UserDataHelper setUserData:connectName forKey:AUTO_RECONNECT_NAME];if (sendTimer.isValid) {[sendTimer setFireDate:[NSDate distantPast]];}//连接后开始发心跳包[[NSRunLoop mainRunLoop] addTimer:sendTimer forMode:NSRunLoopCommonModes];                  //加入到RunLoop中[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:1];}//lxadd读到机器人发来的数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{NSDictionary *dict = [NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableContainerserror:nil];
//    NSLog(@"读取到的数据包信息--==%@",dict);
//    NSLog(@"currentPacktHead==%@",currentPacketHead);
//    NSLog(@"当前线程=--%@",[NSThread currentThread]);//先读取到当前数据包头部信息if (!currentPacketHead) {//当第一次来的是心跳包的时候会出问题currentPacketHead = [NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableContainerserror:nil];//NSLog(@"currentPacketHead---%@",currentPacketHead);NSUInteger packetLength = [currentPacketHead[@"size"] integerValue];if (packetLength == 0) {currentPacketHead = nil;return;}//读到数据包的大小
//        NSLog(@"packetLength:---%ld",packetLength);[sock readDataToLength:packetLength withTimeout:-1 tag:1];return;}if (!currentPacketHead) {NSLog(@"error:当前数据包的头为空");//断开连接return;}//正式的包处理NSUInteger packetLength = [currentPacketHead[@"size"] integerValue];
//    NSLog(@"packetLength--%zd",packetLength);//NSLog(@"data.length--%zd",data.length);
//     NSLog(@"正式包数据--==%@",dict);//说明数据有问题 看正式包的长度是否与包头告诉你的长度一致if (packetLength <= 0 || data.length != packetLength) {NSLog(@"error:当前数据包数据大小不正确");currentPacketHead = nil;return;}NSString *aString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];id jsonMap = [JsonHelper fromJsonString:aString];if (([jsonMap[@"commondType"] integerValue] != 20)) {//表示回的不是心跳包,是有效数据dispatch_async(dispatch_get_main_queue(), ^{[UserDataHelper setUserData:jsonMap[@"robot_version"] forKey:ROBOT_VERSION];if (msgReveiceBlock) {NSLog(@"机器人传回的jsonMap==%@",jsonMap);msgReveiceBlock(jsonMap);//                if ([jsonMap[@"commondType"] integerValue] == [PLAY_RESOURCE_DATA integerValue]){//               NSNotification *notification =[NSNotification notificationWithName:@"fromRobot" object:nil userInfo:jsonMap];
//                [[NSNotificationCenter defaultCenter] postNotification:notification];
//                }}});}else{//表示回的是心跳包[UserDataHelper setUserData:jsonMap[@"hyID"] forKey:Robot_EM_ID];[noSendTimer invalidate];noSendTimer = nil;noSendTimer = [NSTimer scheduledTimerWithTimeInterval:ACCEPT_HEART_TIME_SPACE target:self selector:@selector(robotConnectTimeOut) userInfo:nil repeats:NO];static dispatch_once_t onceToken_id;dispatch_once(&onceToken_id, ^{if (_getIdBlock) {_getIdBlock(jsonMap);}});}currentPacketHead = nil;
//    NSLog(@"fromRobot msg,currentPacketHead,%@",jsonMap);[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:1];}- (void)robotConnectTimeOut
{// NSLog(@"检测是否收到心跳包的定定时器,40秒没收到说明断开了");_connectState = NO;if (socketTool.connectStateBlock) {dispatch_async(dispatch_get_main_queue(), ^{socketTool.connectStateBlock(_connectState);});}[noSendTimer invalidate];noSendTimer = nil;
}- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err
{//lxaddlx 机器人连接失败的超时时长是oc的socket框架定的NSLog(@"lxaddlx已经断开连接了 TCP%@",err);_connectState = NO;if (socketTool.connectStateBlock) {dispatch_async(dispatch_get_main_queue(), ^{socketTool.connectStateBlock(_connectState);});}[sendTimer setFireDate:[NSDate distantFuture]];[socketTool autoConnectTcp:connectName];
}- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock
{NSLog(@"%@",sock);
}#pragma mark - Actions
- (void)sendHeartData
{//NSLog(@"来到发心跳包的定时器");if (!_connectState) {//关掉定时器[sendTimer invalidate];}NSDictionary *writeDic = @{@"commondType":@"19"};// NSLog(@"给机器人发心跳包%@",writeDic);NSMutableData *writeData = [NSMutableData dataWithData:[JsonHelper toJsonData:writeDic]];[writeData appendData:[GCDAsyncSocket CRLFData]];NSUInteger size = writeData.length;NSMutableDictionary *headDic = [NSMutableDictionary dictionary];[headDic setObject:[NSString stringWithFormat:@"%ld",(unsigned long)size] forKey:@"size"];NSData *jsonData = [JsonHelper toJsonData:headDic];// NSLog(@"写入Socket的心跳包%@",headDic);NSMutableData *mData = [NSMutableData dataWithData:jsonData];//分界[mData appendData:[GCDAsyncSocket CRLFData]];[mData appendData:writeData];// NSLog(@"sendHeartData:%@",mData);[asyncSocket writeData:mData withTimeout:-1 tag:1];}//给RB发送指令
- (void)sendMsgToRobot:(NSDictionary*)msgDic{NSMutableData *writeData = [NSMutableData dataWithData: [JsonHelper toJsonData:msgDic]];[writeData appendData:[GCDAsyncSocket CRLFData]];NSUInteger size = writeData.length;NSMutableDictionary *headDic = [NSMutableDictionary dictionary];[headDic setObject:[NSString stringWithFormat:@"%ld",size] forKey:@"size"];//NSLog(@"给机器人发的数据%@",headDic);NSData *jsonData = [JsonHelper toJsonData:headDic];NSMutableData *mData = [NSMutableData dataWithData:jsonData];//分界[mData appendData:[GCDAsyncSocket CRLFData]];[mData appendData:writeData];//NSLog(@"%@",writeData);[asyncSocket writeData:mData withTimeout:-1 tag:1];}@end

3.用微信的Airkiss给机器人配网

4.iOS13后无法获取wifi名的解决

ios13无法获取wifi名(SSID)(亲测有效)

相关博客

Socket简析与iOS实现

iOS wifi(socket)通讯相关推荐

  1. iOS进程间通讯方式

    iOS 进程间通讯方式: 解释 URL Scheme 这个是iOS app通信最常用到的通信方式,App1通过openURL的方法跳转到App2,并且在URL中带上想要的参数,有点类似http的get ...

  2. iOS端Socket连接、发送数据(一)

    一.Socket的应用 IM即时通讯是通过Socket的方式实现长连接,可运用于 (1)直播聊天室.礼物 (2)微信.QQ等即时聊天 (3)游戏对话.技能等 二.SOCKET原理 套接字(socket ...

  3. Android:在同一WiFi下通讯(局域网下服务端和客户端通讯)

    ​ 看了几天的Android WiFi通讯,总结一下,并附相关Demo(也是仿网上做的),建议收藏 ​ 两台设备(手机与手机,手机与硬件都一样)在同一WiFi下通讯,用的是TCP/IP协议,那我们应如 ...

  4. 获取android模拟器的IP地址,Android模拟器的ip获取以及模拟器之间socket通讯

    一.Android  获取本机Mac 地址方法:java 须要在AndroidManifest.xml文件中添加权限:android shell Java代码服务器 public String get ...

  5. Java与C++Socket通讯注意

    2019独角兽企业重金招聘Python工程师标准>>> c++与java进行socket通信时注意事项 因为java发送的都是网络字节序(big-endium),而c++是主机字节序 ...

  6. [置顶] 【C#】 Socket通讯客户端程序

    这段时间一直在优化Socket通讯这块,经常和Socket打交道,现在分享给大家一个小的案例, 代码如下: byte[] m_dataBuffer = new byte [10];         I ...

  7. java与 C++ 之间进行 SOCKET 通讯要点简要解析

    Endian定义: 在计算机系统体系结构中用来描述在多字节数中各个字节的存储顺序. big-endian也称高位在前.大端在前.是 计算机体系结构中一种描述多字节存储顺序的术语,在这种机制中最重要字节 ...

  8. WiFiDemon – iOS WiFi RCE 0-Day漏洞利用

    近日,ZecOps安全研究人员发现了iOS WiFi命名漏洞的零交互攻击利用方式,可以用来远程劫持iPhone设备. Wi-Fi-Demon Wifid 是处理与WiFi连接相关的协议的系统daemo ...

  9. as3 java 交互_求大佬用 Java 实现这段 AS3 的 socket 通讯功能

    最近在分析一个直播网站,初步分析后发现是在 swf 中用 socket 通讯返回的 flv 地址. 其中 Actionscript socket 通讯的关键代码如下: this._socket = n ...

最新文章

  1. windows安装MongoDB环境以及在pycharm中配置可视化插件
  2. Python 动态载入模块
  3. oracle中decode和case的使用例子
  4. React中后台管理系统添加广告分类显示不出来
  5. 5G是什么?5G能做什么?5G在未来将带来什么?
  6. c语言5-34答案,C语言答案第5章.doc
  7. 游戏必备组件有哪些_微信广告将升级小程序、小游戏开发者收入方案
  8. 【免费软件测试视频-0022】——Winrunner系列之---GUI快速脚本向导
  9. 2022腾讯云学生云服务器申请攻略(25岁以下免学生认证)!
  10. [精华] RDMA技术原理分析、主流实现对比和解析
  11. python练手经典100例项目-Python 的练手项目有哪些值得推荐?
  12. 6p14推挽胆机20w功放电路图_6P14推挽双输出牛胆机
  13. 钓鱼邮件攻击(入门)
  14. 致敬不凡·最美的星火:国产飞腾CPU研发力量
  15. 项目管理师、系统分析师和系统架构师的关系与区别
  16. From little Cutie to Rockin Beauty(about Hilary Duff and someone concerned.)
  17. rac 火星舱如何备份oracle_火星舱cdp功能-rpo与rto可以做到什么程度
  18. 大暑节气海报图片|大暑节气海报文案
  19. 卫生部拟规定就业入学等常规体检不再查乙肝
  20. Windows下尝试PHP7提示丢失VCRUNTIME140.DLL的问题解决

热门文章

  1. 在java给别人邮箱发邮件
  2. 如何设计打造一款更适合异性交往的社交App
  3. OSChina 周日乱弹 ——奥运已经变成里约大冒险了
  4. c语言getchar与putchar
  5. 少年成就黑客,需要这些技能
  6. 基于四分之一车体模型加速度的路面平整度检测及评价
  7. 商业企业的供应链管理模型
  8. Activity与调用线(三):Activity生命周期源码解析
  9. 大灯照出来的光有阴影_汽车近光灯前有黑色阴影正常吗
  10. Jerry Wang从2017年到2019年的自由泳学习笔记