iOS 局域网搜索可以使用两种方式。第一种方式局域网广播方式、此方式一般在3秒内就会相应。第二种方式也是比较笨拙的方式通过ping方式、这种方式一般是在硬件本身并不支持广播功能。此方法弊端:搜索时间长。推荐:可以有广播功能的使用第一种方式、没有广播功能和局域网内设备相对较少以及是连接手机wifi热点的情况。

第一种方式 广播:

推荐使用第三方GCDAsynSoket 代码如下:

 

@interface SearchCenter()<GCDAsyncUdpSocketDelegate>
//@property(nonatomic, strong) NSMutableArray *arpTableList;
@property(nonatomic, strong) GCDAsyncUdpSocket *gcdAsyncUdpSocket;
//广播定时器
@property(nonatomic, strong) NSTimer *broadcastTimer;
@end

-(GCDAsyncUdpSocket *)gcdAsyncUdpSocket
{
if (!_gcdAsyncUdpSocket) {

//: CameraBroadCastResponsePort 为设备回调消息过来的监听端口
_gcdAsyncUdpSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err = nil;
[_gcdAsyncUdpSocket enableBroadcast:YES error:&err];
[_gcdAsyncUdpSocket bindToPort: CameraBroadCastResponsePort error:&err];
[_gcdAsyncUdpSocket beginReceiving:&err];
}
return _gcdAsyncUdpSocket;
}

-(NSTimer *)broadcastTimer
{
if (!_broadcastTimer) {
_broadcastTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(broadcastAction) userInfo:nil repeats:YES];
[_broadcastTimer setFireDate:[NSDate distantFuture]];
}
return _broadcastTimer;
}

#pragma mark 广播方式搜索

-(void)startUdpBroadcastAddress:(NSString *)broadcastAddress
{
_broadcastAddress = broadcastAddress;
_currentSearchStatus = KPXSearchStatusSearching;
_searchTimes = 0;
[self.deviceList removeAllObjects];
NSLog(@"开始udp广播");
[self.broadcastTimer setFireDate:[NSDate distantPast]];

}

//广播定时器
-(void)broadcastAction
{
//_broadcastAddress 为广播地址(该地址获取方式请下载代码查看)   CameraBroadCastMonitorPort为硬件设备监听端口
NSData *data = [ CameraUdpBroadCastCmd dataUsingEncoding:NSUTF8StringEncoding];
[self.gcdAsyncUdpSocket sendData:data toHost:_broadcastAddress port: CameraBroadCastMonitorPort withTimeout:-1 tag:0];

}

if (_searchTimes >= 30) {
CameraManager *camraManager = [ CameraManager shareManager];
[camraManager stopSearch];
}

}

#pragma mark GCDAsyncUdpSocketDelegate
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
NSLog(@"udp发送数据");
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error
{
NSLog(@"udp发送出错");
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(nullable id)filterContext
{
NSString *resposeString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(@"resposeString=%@",resposeString);
if ([resposeString containsString:@"ip"]) {
NSString *deviceIp = [GCDAsyncUdpSocket hostFromAddress:address];
// uint16_t port = [GCDAsyncUdpSocket portFromAddress:address];
NSDictionary *dict =[NSDictionary dictionaryWithObjectsAndKeys:deviceIp,@"ipAdress", nil];
if (![self.deviceList containsObject:dict]) {
[self.deviceList addObject:dict];
NSLog(@"发现摄像头:%@待验证",dict);
[self searchPasue];
if (self.delegete && [self.delegete respondsToSelector:@selector(searchDeviceListDidChange)]) {
[self.delegete searchDeviceListDidChange];
}
}else{
//已经添加到设备列表
NSInteger index = [self.deviceList indexOfObject:dict];
[self.deviceList exchangeObjectAtIndex:index withObjectAtIndex:self.deviceList.count-1];
//判断http服务器是否响应已经确认为摄像头
__block BOOL isExist = NO;
CameraManager *camraManager = [ CameraManager shareManager];
[camraManager.onlineCameras enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
Camera *camra = obj;
if ([camra.camerIp isEqualToString:deviceIp]) {
isExist = YES;
*stop = YES;
}
}];

if (isExist == NO && _currentSearchStatus == KPXSearchStatusSearching) {
[self searchPasue];
//摄像头http服务首次未响应待验证
NSLog(@"http服务未响应、正在重试....");
if (self.delegete && [self.delegete respondsToSelector:@selector(searchDeviceListDidChange)]) {
[self.delegete searchDeviceListDidChange];
}
}
}
}

}
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error
{
NSLog(@"udpSocketDidClose");
}

第二种方式ping

1.首先借助苹果官方提供的SimplePing.

代码如下:

.h文件如下

#import <Foundation/Foundation.h>

@interface XplorePing : NSObject
//初始化并开始ping
+( XplorePing *)createPingHostName:(NSString *)hostName finishAction:(void (^)(BOOL isOK))finishAction;
//开始ping
-(void)startPingHostName:(NSString *)hostName finishAction:(void (^)(BOOL isOK))finishAction;
@end

.m文件如下

#import "SimplePing.h"
@interface XplorePing()<SimplePingDelegate>
@property(nonatomic, strong) SimplePing *pinger;
@end

@implementation XplorePing{
int _times;
NSTimer *_timer;
BOOL _pingSuccess;
void (^_pingFinishAction)(BOOL);
}

-(void)dealloc
{
// NSLog(@"被释放了 Ping");
}
+( XplorePing *)createPingHostName:(NSString *)hostName finishAction:(void (^)(BOOL isOK))finishAction
{
XplorePing *ping = [[ XplorePing alloc]init];
[ping startPingHostName:hostName finishAction:finishAction];
return ping;
}

-(void)startPingHostName:(NSString *)hostName finishAction:(void (^)(BOOL isOK))finishAction
{

SimplePing *pinger = [[SimplePing alloc] initWithHostName:hostName];
self.pinger = pinger;
pinger.delegate = self;
pinger.addressStyle = SimplePingAddressStyleAny;//ipv4和ipv6环境
//初始化基本
_pingFinishAction = finishAction;
_pingSuccess = NO;
//清零
_times = 0;
_timer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:@selector(start) userInfo:nil repeats:YES];
[_timer fire];
[[NSRunLoop currentRunLoop]run];


}

-(void)start
{
[self.pinger stop];
[self.pinger start];
_times ++;
if (_times>=5) {
//销毁
[_timer invalidate];
_timer = nil;
[self.pinger stop];
//回调
if (_pingFinishAction) {
_pingFinishAction(_pingSuccess);
}
return;//必须的
}

}

/**
* start成功,也就是准备工作做完后的回调
*/
- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address
{
// NSLog(@"开始ping");
// 发送测试报文数据
[self.pinger sendPingWithData:nil];
}

- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error
{
NSLog(@"didFailWithError");
[self.pinger stop];
}

// 发送测试报文成功的回调方法
- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
{
NSLog(@"#%u sent", sequenceNumber);
}

//发送测试报文失败的回调方法
- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error
{
NSLog(@"#%u send failed: %@", sequenceNumber, error);
}

// 接收到ping的地址所返回的数据报文回调方法
- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
{
NSLog(@"#%u received, size=%zu", sequenceNumber, packet.length);
//标记成功
_pingSuccess = YES;
[_timer invalidate];
_timer = nil;
[self.pinger stop];

if (_pingFinishAction) {
_pingFinishAction(_pingSuccess);
}

}

- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet
{
NSLog(@"#%s",__func__);
}

@end

 

 广播地址获取以及源码获取:https://files.cnblogs.com/files/ChangeStrong/WifiManager.zip 有什么不明白的请留言或者加Q:491337430