iOS在工程中ping某个服务节点

最近在做项目时需要个需求,是需要对某个节点的判断 连接的ping值和网速,查阅资料时看到了苹果的一个demo:SimplePing
然后根据苹果的demo写了个工具判断网络延迟和丢包率

1.苹果的demo是定时器发送一个ping,请求会带有标志sequenceNumber
2.然后在回调delegate方法里,也会带有sequenceNumber,这样就可以判断是哪个请求

我这里用一个对象数组,存储每次ping的发送时间和回调时间,在定时器结束时判断回调了多少次来算丢包率,逻辑很简单

所以大家有空的话可以自己看苹果的demo,自己封装一个,省事的话可以用我这个


  • 1.头文件 在pingTimeLength时间内执行pingTimes次ping
@interface MDPing : NSObject

/** ping多长时间,默认1s */
@property (nonatomic) CGFloat pingTimeLength;

/** ping多少次,默认10 */
@property (nonatomic) NSInteger pingTimes;
/**
 开启对ip点的丢包率和延迟检测
 
 @param hostName 检测点
 @param callBack 回调
 */
- (void)startWithHostName:(NSString *)hostName callBack:(void(^)(int pingValue,float lossRate))callBack;
@end
  • 2.开始执行定时器轮训ping
    这里我起了个异步线程,为的是不打扰主线程的UI操作,并且runloop开启线程
    定时器到固定的时间后会清空pinger,线程停止
if (!_workQueue) {
        _workQueue = dispatch_queue_create("ping.workqueue", DISPATCH_QUEUE_CONCURRENT);
    }
    dispatch_async(_workQueue, ^{
        self.callBack = callBack;
        self.pingValus = @[].mutableCopy;
        
        assert(self.pinger == nil);
        
        self.pinger = [[SimplePing alloc] initWithHostName:hostName];
        assert(self.pinger != nil);
        
        if (self.forceIPv4 && ! self.forceIPv6) {
            self.pinger.addressStyle = SimplePingAddressStyleICMPv4;
        } else if (self.forceIPv6 && ! self.forceIPv4) {
            self.pinger.addressStyle = SimplePingAddressStyleICMPv6;
        }
        
        self.pinger.delegate = self;
        [self.pinger start];
        
        do {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        } while (self.pinger != nil);
    });
  • 3.执行定时器清空和数据返回
    didStartWithAddress这个方法是连接成功后的回调
- (void)sendPing {
    assert(self.pinger != nil);
    [self.pinger sendPingWithData:nil];
    
    PingValue *value = [PingValue new];
    value.startPingTime = [NSDate date].timeIntervalSince1970;
    [_pingValus addObject:value];
    
    if (_pingValus.count >= _pingTimes) {
        [self.sendTimer invalidate];
        self.sendTimer = nil;
        self.pinger = nil;
    }
}

- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address {
#pragma unused(pinger)
    assert(pinger == self.pinger);
    assert(address != nil);
    
    // Send the first ping straight away.
    
    [self sendPing];
    
    // And start a timer to send the subsequent pings.
    assert(self.sendTimer == nil);
    self.sendTimer = [NSTimer scheduledTimerWithTimeInterval:_pingTimeLength/_pingTimes target:self selector:@selector(sendPing) userInfo:nil repeats:YES];
    
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((_pingTimeLength+0.1) * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        
        [self.sendTimer invalidate];
        self.sendTimer = nil;
        self.pinger = nil;
        
        if (self.callBack) {
            double x = 0;
            int backTimes = 0;
            for (PingValue *value  in self.pingValus) {
                
                if (value.backTime != 0) {
                    x += (value.backTime-value.startPingTime);
                    backTimes ++;
                }
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                self.callBack(x*1000/backTimes, 1-(backTimes/(self.pingValus.count *1.f)));
            });
            
        }
    });
}
  • 4.每次收到ping回调
- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber {
#pragma unused(pinger)
    assert(pinger == self.pinger);
#pragma unused(packet)
    NSLog(@"#%u received, size=%zu", (unsigned int) sequenceNumber, (size_t) packet.length);
    if (sequenceNumber<_pingValus.count) {
        _pingValus[sequenceNumber].backTime = [NSDate date].timeIntervalSince1970;
    }
    
}

到这里所有的操作的都完成了,我写的很简单,基本就是把苹果demo拿来改下

你可能感兴趣的:(iOS在工程中ping某个服务节点)