最近在做项目时需要个需求,是需要对某个节点的判断 连接的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拿来改下,如果有什么不对的地方,请指教下
已经上传到pod,pod引用:
pod 'MDPing'
网友评论