最近在做一個(gè)VPN工具(https://itunes.apple.com/us/app/bigvpn/id1225850922?mt=8)摹闽,考慮到類(lèi)似的網(wǎng)絡(luò)工具需要一個(gè)ping功能涕刚,即檢測(cè)當(dāng)前網(wǎng)絡(luò)環(huán)境和服務(wù)器的連接狀態(tài)腥寇,像是PC端的命令行工具ping饥努。于是在Apple的官方demo的基礎(chǔ)上進(jìn)行了了封裝萤悴,實(shí)現(xiàn)實(shí)時(shí)顯示當(dāng)前網(wǎng)絡(luò)連接服務(wù)器的延遲陌选,實(shí)現(xiàn)比較簡(jiǎn)單常遂,如下:
- 聲名屬性變量。
@interface WHPingTester()<SimplePingDelegate> { NSTimer* _timer; //不斷發(fā)送ping命令的定時(shí)器 NSDate* _beginDate; // 單個(gè)ping 發(fā)送時(shí)的時(shí)間 } @property(nonatomic, strong) SimplePing* simplePing; //Apple的ping工具 @property(nonatomic, strong) NSMutableArray<WHPingItem*>* pingItems; //WHPingItem表示每一個(gè)ping包侥锦,pingItems是以隊(duì)列的形式存儲(chǔ)和刪除 @end
- 在開(kāi)啟ping命令之前必須對(duì)simplePing進(jìn)行相關(guān)設(shè)置:
self.simplePing = [[SimplePing alloc] initWithHostName:hostName];
self.simplePing.delegate = self;
self.simplePing.addressStyle = SimplePingAddressStyleAny;// 網(wǎng)絡(luò)類(lèi)型
self.pingItems = [NSMutableArray new]; //初始化緩存
- 調(diào)用start方法開(kāi)啟ping命令:
[self.simplePing start];
如果該方法成功執(zhí)行进栽,則以下函數(shù)會(huì)被回調(diào)。
- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address
{
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendPingData) userInfo:nil repeats:YES]; //開(kāi)啟定時(shí)器恭垦,不斷發(fā)送ping包
}
- sendPingData很簡(jiǎn)單:
- (void) sendPingData
{
[self.simplePing sendPingWithData:nil];
}
- 方法sendPingWithData發(fā)送成功后快毛,以下函數(shù)會(huì)被調(diào)用(回調(diào))
- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
{
WHPingItem* item = [WHPingItem new];
item.sequence = sequenceNumber;
[self.pingItems addObject:item];
_beginDate = [NSDate date];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if([self.pingItems containsObject:item])
{
NSLog(@"超時(shí)---->");
[self.pingItems removeObject:item];
if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingSucccessWithTime:withError:)])
{
[self.delegate didPingSucccessWithTime:0 withError:[NSError errorWithDomain:NSURLErrorDomain code:111 userInfo:nil]];
}
}
});
}
在該回調(diào)方法里面,我創(chuàng)建了一個(gè)item對(duì)象番挺,表示一個(gè)ping包唠帝,將其加入pingItems緩存里。并將開(kāi)始時(shí)間_beginDate設(shè)置為當(dāng)前的時(shí)間玄柏,最后在1.5秒之后檢測(cè)緩存里面是否還有還對(duì)象襟衰,如果有(解釋見(jiàn)第6點(diǎn)),說(shuō)明網(wǎng)絡(luò)不通粪摘,最后將其從緩存中將其移除瀑晒。
- 如果收到服務(wù)器的反饋包,則以下函數(shù)會(huì)被調(diào)用:
- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber
{
float delayTime = [[NSDate date] timeIntervalSinceDate:_beginDate] * 1000;
[self.pingItems enumerateObjectsUsingBlock:^(WHPingItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if(obj.sequence == sequenceNumber)
{
[self.pingItems removeObject:obj];
}
}];
if(self.delegate!=nil && [self.delegate respondsToSelector:@selector(didPingSucccessWithTime:withError:)])
{
[self.delegate didPingSucccessWithTime:delayTime withError:nil];
}
}
如上徘意,一旦收到反饋包苔悦,則按照序號(hào)刪掉緩存里面相應(yīng)的item(包),delayTime則為收到包的時(shí)間與開(kāi)始時(shí)間之差椎咧。
為了方便大家使用玖详,我已經(jīng)將該demo簡(jiǎn)單的封裝了一下并上傳到了github,地址:https://github.com/wanghe826/PingTool