使用 Java/Android 测量下载速度
Posted
技术标签:
【中文标题】使用 Java/Android 测量下载速度【英文标题】:Measuring Download Speed with Java/Android 【发布时间】:2012-08-28 11:21:07 【问题描述】:我正在开发一个 android 应用程序,我需要尽可能准确地测量当前连接的下载速度。这是迄今为止我能找到的最好的方法(基本上我启动一个计时器,开始从快速服务器下载 Linux 发行版,下载大约 200 KB,然后停止计时器并检查经过的时间和下载的总字节数):
try
InputStream is = new URL("http://www.domain.com/ubuntu-linux.iso").openStream();
byte[] buf = new byte[1024];
int n = 0;
startBytes = TrafficStats.getTotalRxBytes(); /*gets total bytes received so far*/
startTime = System.nanoTime();
while(n<200)
is.read(buf);
n++;
endTime = System.nanoTime();
endBytes = TrafficStats.getTotalRxBytes(); /*gets total bytes received so far*/
totalTime = endTime - startTime;
totalBytes = endBytes - startBytes;
catch(Exception e)
e.printStackTrace();
之后,我只需要将传输的字节数除以所用时间,就可以得出下载速度(以 bps 为单位)。
问题: 1. 这种方法准确吗? 2. 你知道更好的吗?
非常感谢。
【问题讨论】:
他们现在设置它的方式,它不会是准确的。InputStream.read
不能保证完全填满你的缓冲区。您需要检查返回值以查看实际读取了多少 byte
s。
@Jeffrey,您没有详细阅读代码。我不依赖 read() 来获取字节数。我通过 getTotalRxBytes() 函数直接从操作系统获取它。
啊,我的错。我确实略过了那部分。您的解决方案或多或少是准确的。
@Jeffrey,谢谢。如果您对如何使它更多有任何想法,请告诉我。
【参考方案1】:
这里有几个可能的问题:
如果您希望在任意设备上即时执行此操作(相对于实验室设置),您需要遵循 Jeffrey 的建议,因为其他应用程序可能会消耗 @987654321 报告的带宽@。
这会测试来自该主机的下载速度。如果那是您将要与“真实的东西”交流的主机,那就太酷了。或者,如果您一般只需要了解下载速度,也可以。但是测试站点 A 的下载速度并假设站点 B 的下载速度是不可靠的,因为站点 A 和站点 B 甚至可能不在同一个大陆上。
如果您希望经常这样做,您正在测试的主机的所有者可能会对带宽费用、过多的日志条目等感到轻微的恼火。理想情况下,您只会针对您拥有的东西执行此操作.
对于按流量计费的数据计划,200KB 可能会激怒设备所有者。
关于互联网访问(例如,服务器可能已关闭)和移动设备(例如,用户可能开始使用 WiFi 并移出范围,从而极大地改变您的下载能力)的所有标准警告都适用。
话虽如此,下载是衡量下载速度的唯一真正方法。
【讨论】:
关于第一点:“其他应用程序可以消耗 getTotalRxBytes() 报告的带宽”如果想法是测量带宽,那么可以使用 getTotalRxBytes(),因为如果其他应用消耗带宽,您想在计算中考虑这一点。【参考方案2】:使用下面的代码。我用它来测量下载速度。 您不需要为了测量下载速度而保存文件。您也可能不需要使用 OkHttp。我使用它是因为它在我们的项目中使用过。
String downloadURL = "http://test.talia.net/dl/1mb.pak";
MediaType FILE = MediaType.parse("multipart/form-data;");
OkHttpClient downloadClient = new OkHttpClient().newBuilder()
.build();
Request download = new Request.Builder()
.url(downloadURL)
.build();
downloadClient.newCall(download).enqueue(new Callback()
@Override
public void onFailure(Call call, IOException e)
@Override
public void onResponse(Call call, Response response) throws IOException
if(response!=null)
long startTime = System.currentTimeMillis();
InputStream is = response.body().byteStream();
BufferedInputStream bis = new BufferedInputStream(is);
long size = 0;
int red = 0;
byte[] buf = new byte[1024];
while ((red = bis.read(buf)) != -1)
size += red;
long endTime = System.currentTimeMillis();
double rate = (((size / 1024) / ((endTime - startTime) / 1000)) * 8);
rate = Math.round( rate * 100.0 ) / 100.0;
String ratevalue;
if(rate > 1000)
ratevalue = String.valueOf(rate / 1024).concat(" Mbps");
else
ratevalue = String.valueOf(rate).concat(" Kbps");
if(is!=null)
is.close();
if(bis!=null)
bis.close();
Log.d("download", "download speed = " + ratevalue);
);
【讨论】:
【参考方案3】:采样方法有很多种,没有一种“真正”的速度。您可以查看以下标准,让您更了解推荐的方式:
https://itu.int/en/ITU-T/C-I/Pages/IM/Internet-speed.aspx
https://itu.int/itu-t/recommendations/rec.aspx?rec=q.3960
https://itu.int/ITU-T/recommendations/rec.aspx?rec=14125
https://tools.ietf.org/pdf/rfc6349.pdf
您提出的代码使用 1 个线程测试速度。不推荐这种方式,因为它不会最大化互联网连接的全部容量。大多数标准都推荐多线程测试。
您还可以使用我们的 Android SDK,它应该可以满足您的需求并符合 ITU 标准:
https://github.com/speedchecker/speedchecker-sdk-android
【讨论】:
以上是关于使用 Java/Android 测量下载速度的主要内容,如果未能解决你的问题,请参考以下文章