最近在做項(xiàng)目時(shí)需要個(gè)需求,是需要對(duì)某個(gè)節(jié)點(diǎn)的判斷 連接的ping值和網(wǎng)速,查閱資料時(shí)看到了蘋(píng)果的一個(gè)demo:SimplePing
然后根據(jù)蘋(píng)果的demo寫(xiě)了個(gè)工具判斷網(wǎng)絡(luò)延遲和丟包率
1.蘋(píng)果的demo是定時(shí)器發(fā)送一個(gè)ping,請(qǐng)求會(huì)帶有標(biāo)志sequenceNumber
2.然后在回調(diào)delegate方法里,也會(huì)帶有sequenceNumber,這樣就可以判斷是哪個(gè)請(qǐng)求
我這里用一個(gè)對(duì)象數(shù)組,存儲(chǔ)每次ping的發(fā)送時(shí)間和回調(diào)時(shí)間,在定時(shí)器結(jié)束時(shí)判斷回調(diào)了多少次來(lái)算丟包率,邏輯很簡(jiǎn)單
所以大家有空的話可以自己看蘋(píng)果的demo,自己封裝一個(gè),省事的話可以用我這個(gè)
- 1.頭文件 在pingTimeLength時(shí)間內(nèi)執(zhí)行pingTimes次ping
@interface MDPing : NSObject
/** ping多長(zhǎng)時(shí)間,默認(rèn)1s */
@property (nonatomic) CGFloat pingTimeLength;
/** ping多少次,默認(rèn)10 */
@property (nonatomic) NSInteger pingTimes;
/**
開(kāi)啟對(duì)ip點(diǎn)的丟包率和延遲檢測(cè)
@param hostName 檢測(cè)點(diǎn)
@param callBack 回調(diào)
*/
- (void)startWithHostName:(NSString *)hostName callBack:(void(^)(int pingValue,float lossRate))callBack;
@end
- 2.開(kāi)始執(zhí)行定時(shí)器輪訓(xùn)ping
這里我起了個(gè)異步線程,為的是不打擾主線程的UI操作,并且runloop開(kāi)啟線程
定時(shí)器到固定的時(shí)間后會(huì)清空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.執(zhí)行定時(shí)器清空和數(shù)據(jù)返回
didStartWithAddress這個(gè)方法是連接成功后的回調(diào)
- (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回調(diào)
- (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;
}
}
到這里所有的操作的都完成了,我寫(xiě)的很簡(jiǎn)單,基本就是把蘋(píng)果demo拿來(lái)改下