目录
常见的下行测速方案
1、使用XHR接口,通过返回的数据包大小和消耗时间,可以计算出下行网速
使用复方案的有: 网飞测速 fast.com,speedtest.net,speed.cloudflare.com 等
2、还有部分网站提供的flash测速方案,然而这已经是个废弃的技术。
例如:电信提供的测速网站
3、 通过<img> <script> <link> 标签加载特定大小的链接,再除以耗时可以获得对应加载速度。
优点:可以跨域
缺点:需要知道加载文件大小,如果是图片,不方便指定图片大小
通过 Performance接口测速
前几天看到了Performance接口,发现可以很方便获取到页面和页面资源加载信息。经过一段时间对Performance.timing的研究,决定采用通过加载图片进行测速。后续通过后端输出指定大小图片以挤满带宽。
页面响应时间(近似ping)
(function (){
let t =window.performance.timing
console.log('DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart))
console.log('TCP链接耗时:'+(t.connectEnd - t.connectStart))
console.log('加载静态小资源时近似ping:'+(t.responseStart - t.requestStart ))
console.log('request请求耗时:'+(t.responseEnd -t.responseStart ))
})()
下行速度
var iTime = performance.getEntriesByName('a.png')[0];
console.log('接收耗时:'+(iTime.responseEnd - iTime.responseStart))
console.log('文件大小:'+(iTime.decodedBodySize))
console.log('speed:' + ((c * 8000 / t / 1000 / 1000)).toFixed(3) + ' Mbit/S')
php 构造 指定大小图片
<?php
if(!empty($_GET['_down'])){
ini_set('memory_limit', '400M');
$test_cnt = 2;
$c = floor(strtr(($_GET['_down']),['.png'=>''])/$test_cnt);
$c = [1,1,10,25,50,100,200,512,1024][$c];
header("Content-type: image/x-png");
$im = imagecreatetruecolor(334, $c * 1000);
imagepng($im,null,0);
imagedestroy($im);
exit;
}
?>
前端代码
前端测速的策略
1、当下载时间2次超过1.2s,视为极限速度
2、loading_cnt 可以跳转总测速次数,配合后端的$test_cnt,可以调整测速周期
speedtest DEMO
结果
本地测速
浏览器chrome ,在devtool设置中【Throttling】增加对应带宽限制方案
按F12开启devtool面板,加载对应方案
1M
10M
20M
50M
100M
无限制
在线测速
测速链接
ping值对比
服务器带宽 10M
测速结果
服务器带宽 20M
测速结果
总结
1、测出来的速度为 服务器网速、本地网速、服务端脚本支持最大测速中的最小值。
2、改方案为单线程,测速上限很大会受限于服务端输出图片大小上限
后续更新
前文中后端通过php-gd扩展输出指定大小图片的方案有个致命的缺点,当输出较大图片时,将需要巨大的内存。
后端改进方案,不使用GD扩展,直接在图片后面填充足够长度的字符串。
尝试过对png 等图片格式的研究,思路是直接修改二进制中表示图片长度,并在后续结构体填充足够长度,发现有点复杂,遂放弃。 PNG文件格式详解
在直接输出字符串前端报错后,有了后续思路,生成一个很小的png,作为前段信息,后段填充字符串,这样浏览器在img标签加载完解析图片会成功触发load事件,而不是失败调用error事件。
下文代码的说明
1、使用GD生成一个1*1的png
2、通过ob_get_length获取图片长度,计算填充长度
3、继续填充字符串到指定长度
if (!empty($_GET['_down'])) {
ini_set('memory_limit', '2M');
$c = floor(strtr(($_GET['_down']), ['.png' => '']) / 2);
$c = [1, 1, 10, 25, 50, 100, 150, 200, 512, 1024][$c];
header('Content-Type: image/x-png');
$im = imagecreatetruecolor(1, 1);
ob_start();
imagepng($im, null, 0);
imagedestroy($im);
$l = ob_get_length();
ob_end_flush();
$l = $c * 1024 * 1024 - $l;
for ($i = 0; $i < $l; $i += 1024) {
echo str_pad('0', $i + 1024 > $l ? ($l - $i) : 1024, '0');
}
exit;
}
优化版本
1、跳过GD生成一个1*1的png,直接转化为base64,直接写在代码里,后续在通过base64_decode在转化为二进制输出。(这样直接可以不用GD扩展)
2、跳过长度计算,为固定值90
3、继续填充字符串到指定长度
if(!empty($_GET['_down'])){
ini_set('memory_limit', '2M');
$c = floor(strtr(($_GET['_down']),['.png'=>''])/2);
$c = [1,1,10,25,50,100,150,200,512,1024][$c];
header ('Content-Type: image/x-png');
header ('Content-Length:'.($c * 1024*1024));
echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAADElEQVQI12NgYGAAAAAEAAEnNCcKAAAAAElFTkSuQmCC');
$l = $c * 1024*1024 - 90;
for ($i=0;$i<$l;$i+=1024){
echo str_pad('0',$i+1024>$l?($l-$i):1024,'0');
}
exit;
}
本地无限制测速
意外发现该方案还提高了吞吐量,后续再研究
Performance
Performance 接口可以获取到当前页面中与性能相关的信息
[详细可见 MDS WEB DOC](Performance https://developer.mozilla.org/zh-CN/docs/Web/API/Performance)