网络测速步骤

需求:
在数据中获取 5 个离当前位置最近的服务器作为目标服务器进行网络测速。以测试图片下载速度的形式对下行网速进行模拟测速,以上传一个随机 1M文件速度对上行速度进行模拟测速;共计 25 秒。该篇文章以测试一个服务器为例模拟网络测速过程。

demo 链接:https://share.weiyun.com/56sSBhy

一、解析 XML 格式 数据

  • 解析数据获取服务器列表:
    解析网址数据,并获取 标签下的 server 列表(即获取所有的服务器)。
    每一条 数据中包含url(服务器地址)、lat(纬度)、lon(经度)、name(名字)、sponsor(主办者)、id(id 标识)

    网络测速步骤_第1张图片
    serversList.png
    图片网址:https://share.weiyun.com/5qd6KB6

  • 计算当前位置与服务器的距离并选出距离最近的 5 个服务器:
    获取每一个服务器的经度(lon)和纬度(lat),并通过SpeedTestTool类中的方法- (void)speedCalculateDistanceWithViewController:(UIViewController *)viewController longitude:(double)longitude latitude:(double)latitude distanceBlock:(DistanceBlock)distanceBlock;计算出该服务器与当前位置的距离,找出离当前位置最近的 5 个服务器分别为 s1、s2、s3、s4、s5。

serverData.png
图片网址: https://share.weiyun.com/5xfIjC8

获取地理位置代码示例如下:

[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"];

  • 获取当前已下载的图片的大小及图片总的大小:
  1. 使用 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;
  1. 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]];
}
  • 启动定时器,计算下载速度,并旋转指针:
  1. receivedSize 存储在数组 arrSpeed 中,用于计算接收文件的差值。
[self.arrSpeed addObject:[NSNumber numberWithInteger:self.receivedSizes]];

  1. 获取数组 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]];

  1. 调用 SpeedTestTool 类中 - (NSString *)showSpeedTextWithMB:(double)MB isRealNetSpeed:(BOOL)isRealNetSpeed;方法获取显示在 label 上的速度的字符串。
NSString *showSpeed = [self.speedTool showSpeedTextWithMB:speedMB / 8 isRealNetSpeed:NO];
self.labSpeed.text = showSpeed;

  1. 获取数组 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);
}

你可能感兴趣的:(网络测速步骤)