需求:
在数据中获取 5 个离当前位置最近的服务器作为目标服务器进行网络测速。以测试图片下载速度的形式对下行网速进行模拟测速,以上传一个随机 1M文件速度对上行速度进行模拟测速;共计 25 秒。该篇文章以测试一个服务器为例模拟网络测速过程。
demo 链接:https://share.weiyun.com/56sSBhy
一、解析 XML 格式 数据
-
解析数据获取服务器列表:
图片网址:https://share.weiyun.com/5qd6KB6
解析网址数据,并获取
标签下的 server 列表(即获取所有的服务器)。
每一条
数据中包含url
(服务器地址)、lat
(纬度)、lon
(经度)、name
(名字)、sponsor
(主办者)、id
(id 标识)
计算当前位置与服务器的距离并选出距离最近的 5 个服务器:
获取每一个服务器的经度(lon
)和纬度(lat
),并通过SpeedTestTool
类中的方法- (void)speedCalculateDistanceWithViewController:(UIViewController *)viewController longitude:(double)longitude latitude:(double)latitude distanceBlock:(DistanceBlock)distanceBlock;
计算出该服务器与当前位置的距离,找出离当前位置最近的 5 个服务器分别为 s1、s2、s3、s4、s5。
获取地理位置代码示例如下:
[self.speedTool speedCalculateDistanceWithViewController:self longitude:116.3917 latitude:39.9139 distanceBlock:^(double distance, CLLocation * _Nonnull currentLocation) {
NSLog(@"%f,%f,%f",currentLocation.coordinate.longitude,currentLocation.coordinate.latitude,distance);
}];
二、获取网络延迟
-
获取主机地址:
使用SpeedTestTool
类中- (NSString *)speedCutOutUrlString:(NSString *)urlString;
方法获取 s1、s2、s3、s4、s5 这5 个服务器url
标签中的主机地址。例:url
"http://www2.unicomtest.com:80/speedtest/upload.php"
调用这个方法后获取的主机地址就为www2.unicomtest.com
。获取主机地址示例代码如下:
NSString *strUrl = @"http://nmgspeedtest1.ffcs.cn:80/speedtest/upload.jsp";
NSString *mainframe = [self.speedTool speedCutOutUrlString:strUrl];
- 获取 s1、s2、s3、s4、s5 这5 个服务器的平均网络延迟:
通过STDPingServices
类中
+ (STDPingServices *)startPingAddress:(NSString *)address callbackHandler:(void(^)(STDPingItem *item, NSArray *pingItems))handler;
方法获取 s1、s2、s3、s4、s5 这5 个服务器的网络延迟。每一个服务器获取 5 次网络延迟,计算这个服务器的平均网络延迟,依照这样的方法计算剩下 4 个服务器的平均网络延迟,最后取得 5 个服务器的平均网络延迟最为最终的网络延迟。
获取网络延迟代码示例如下:
//获取网络延迟
self.pingServices = [STDPingServices startPingAddress:@"www2.unicomtest.com" callbackHandler:^(STDPingItem *pingItem, NSArray *pingItems) {
if (pingItem.status != STDPingStatusFinished) {
NSLog(@"网络延迟 %.0fms", pingItem.timeMilliseconds);
}else {
//NSLog(@"%@", [STDPingItem statisticsWithPingItems:pingItems]);
}
}];
三、测试下载速度
-
获取测速图片的 url:
使用SpeedTestTool
类中- (NSString *)changeImageUrlStringWithServerUrlString:(NSString *)urlString;
方法获取即将测试下载速度的图片 url。例:url
http://www2.unicomtest.com:80/speedtest/upload.php
调用这个方法后获取的下载图片的 url 为http://www2.unicomtest.com:80/speedtest/random1000x1000.jpg
获取图片 url 示例代码如下:
NSString *imgUrlString = [self.speedTool changeImageUrlStringWithServerUrlString:@"http://www2.unicomtest.com:80/speedtest/upload.php"];
- 获取当前已下载的图片的大小及图片总的大小:
- 使用
SDWebImage
三方库中- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock completed:(nullable SDExternalCompletionBlock)completedBlock;
方法,在progressBlock
中获取图片的下载进度(receivedSize
,用于计算网速) 和 图片大小(expectedSize
,用于判断图片是否下载完成),并将这两个值赋给全局变量。
self.receivedSizes = receivedSize;
self.expectedSizes = expectedSize;
- 当
receivedSize == expectedSize && expectedSize != 0
的时候证明当前图片已经下载完成,可以进行下一个服务器的下载速度测试或进行上传测试或停止测试。
if (receivedSize == expectedSize && receivedSize != 0)
{
[self scheduleFinish];
}
*注:方法中 options
的参数应为SDWebImageRefreshCached
,这是为了避免当图片已经下载时 SDWebImage 直接调用缓存中图片的情况。
整体代码如下:
- (void)monitorDownloadSpeed
{
NSString *imgUrlString = [self.speedTool changeImageUrlStringWithServerUrlString:@"http://www2.unicomtest.com:80/speedtest/upload.php"];
UIImageView *img = [[UIImageView alloc] init];
[img sd_setImageWithURL:[NSURL URLWithString:imgUrlString] placeholderImage:nil options:SDWebImageRefreshCached progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
self.receivedSizes = receivedSize;
self.expectedSizes = expectedSize;
if (receivedSize == expectedSize && receivedSize != 0)
{
[self scheduleFinish];
}
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
NSLog(@"%ld",cacheType);
NSLog(@"%@",error);
}];
}
- (void)scheduleFinish
{
double sumSpeed = 0.0;
double lastSpeed = ((NSNumber *)self.arrNetSpeed.lastObject).doubleValue;
[self.timer invalidate];
self.timer = nil;
[self.arrNetSpeed removeObjectAtIndex:0];
for (NSInteger speed = 0; speed < self.arrNetSpeed.count; speed++)
{
sumSpeed += ((NSNumber *)self.arrNetSpeed[speed]).doubleValue;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.netSpeedView beginAnimationWithStartValueMbps:lastSpeed endValueMbps:0.0 animationKey:Animation_Key animationValue:Animation_Value];
self.labSpeed.text = [NSString stringWithFormat:@"%.2fMb/s",(sumSpeed / self.arrNetSpeed.count)];
[self clearAllData]; //这个操作必须在主线程上,否则可能会出现数据在子线程上操作提前被清空的情况
});
}
//清空数组
- (void)clearAllData
{
self.receivedSizes = 0;
self.expectedSizes = 0;
[self.arrSpeed removeAllObjects];
[self.arrNetSpeed removeAllObjects];
[self.arrSpeed addObject:[NSNumber numberWithDouble:0.0]];
[self.arrNetSpeed addObject:[NSNumber numberWithDouble:0.0]];
}
- 启动定时器,计算下载速度,并旋转指针:
- 将
receivedSize
存储在数组arrSpeed
中,用于计算接收文件的差值。
[self.arrSpeed addObject:[NSNumber numberWithInteger:self.receivedSizes]];
- 获取数组
arrSpeed
中最后一个值(speed2
) 和 倒数第二个值(speed1
) ,使用SpeedTestTool
类中- (double)currentSpeedUnitConvertWithByets:(double)bytes isRealNetSpeed:(BOOL)isRealNetSpeed;
方法计算速度 (speedMB
),并将speedMB
存入arrNetSpeed
数组中。
//获取接收文件的差值
NSInteger speed2 = ((NSNumber *)self.arrSpeed.lastObject).integerValue;
NSInteger speed1 = ((NSNumber *)self.arrSpeed[self.arrSpeed.count - 2]).integerValue;
//当前速度
double speedMB = [self.speedTool currentSpeedUnitConvertWithByets:((double)speed2 - speed1) isRealNetSpeed:NO];
[self.arrNetSpeed addObject:[NSNumber numberWithDouble:speedMB]];
- 调用
SpeedTestTool
类中- (NSString *)showSpeedTextWithMB:(double)MB isRealNetSpeed:(BOOL)isRealNetSpeed;
方法获取显示在 label 上的速度的字符串。
NSString *showSpeed = [self.speedTool showSpeedTextWithMB:speedMB / 8 isRealNetSpeed:NO];
self.labSpeed.text = showSpeed;
- 获取数组
arrNetSpeed
中最后一个值(netSpeed2
) 和 倒数第二个值(netSpeed1
),计算两个速度之间的差值,并旋转指针。
double netSpeed2 = ((NSNumber *)self.arrNetSpeed.lastObject).doubleValue;
double netSpeed1 = ((NSNumber *)self.arrNetSpeed[self.arrNetSpeed.count - 2]).doubleValue;
[self.netSpeedView beginAnimationWithStartValueMbps:netSpeed1 endValueMbps:netSpeed2 animationKey:Animation_Key animationValue:Animation_Value];
整体代码如下:
- (void)Timered:(NSTimer *)timer
{
if (self.receivedSizes != 0)
{
[self.arrSpeed addObject:[NSNumber numberWithInteger:self.receivedSizes]];
//获取接收文件的差值
NSInteger speed2 = ((NSNumber *)self.arrSpeed.lastObject).integerValue;
NSInteger speed1 = ((NSNumber *)self.arrSpeed[self.arrSpeed.count - 2]).integerValue;
//当前速度
double speedMB = [self.speedTool currentSpeedUnitConvertWithByets:((double)speed2 - speed1) isRealNetSpeed:NO];
NSLog(@"%f",speedMB);
//显示的速度
NSString *showSpeed = [self.speedTool showSpeedTextWithMB:speedMB / 8 isRealNetSpeed:NO];
self.labSpeed.text = showSpeed;
//计算两个速度之间的差值,为动画旋转做准备
[self.arrNetSpeed addObject:[NSNumber numberWithDouble:speedMB]];
double netSpeed2 = ((NSNumber *)self.arrNetSpeed.lastObject).doubleValue;
double netSpeed1 = ((NSNumber *)self.arrNetSpeed[self.arrNetSpeed.count - 2]).doubleValue;
[self.netSpeedView beginAnimationWithStartValueMbps:netSpeed1 endValueMbps:netSpeed2 animationKey:Animation_Key animationValue:Animation_Value];
}
}
三、测试上传速度
上传速度和下载速度的定时器方法大致一样,这里只介绍测试上传速度的流程及如何监测上传进度。
- 获取随机数:
使用SpeedTestTool
类中- (double)getRandomNumber;
方法获取随机数,以便拼接测试上传速度的网址。
double randomNum = [self.speedTool getRandomNumber];
NSString *requestUrl = [NSString stringWithFormat:@"%@?r=%f",serverUrl,randomNum];
- 生成上传文件:
生成一个上传文件,文件可以是 image 类型,也可以是其他文件类型,这里以 1 个 1M 大小的图片为例:
NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"img_upload"], 1.0f);
NSString *encodedImageStr = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
- 上传文件:
上传文件:
[CSDA_DataHelperUserInfo asynchronousPOSTWithURLString:requestUrl delegate:self bodyString:encodedImageStr PassBlock:^(NSData *data) {
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
- 监测上传进度:
如果使用的是系统方法,则需要调用系统方法的上传;如使用第三方,自行调用第三方监测方法:
//监测进度
- (void)URLSession:(NSURLSession *)session task:(nonnull NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
NSLog(@"%lld",totalBytesSent);
}
整体代码如下:
- (void)monitorUploadSpeed
{
NSString *serverUrl = @"http://www2.unicomtest.com:80/speedtest/upload.php";
double randomNum = [self.speedTool getRandomNumber];
NSString *requestUrl = [NSString stringWithFormat:@"%@?r=%f",serverUrl,randomNum];
//图片转成 string
NSData *data = UIImageJPEGRepresentation([UIImage imageNamed:@"img_upload"], 1.0f);
NSString *encodedImageStr = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
[CSDA_DataHelperUserInfo asynchronousPOSTWithURLString:requestUrl delegate:self bodyString:encodedImageStr PassBlock:^(NSData *data) {
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
}
//监测进度
- (void)URLSession:(NSURLSession *)session task:(nonnull NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
NSLog(@"%lld",totalBytesSent);
}