Java实现http请求文件流对带宽限速获取md5值
场景:
当进行http请求获取大数据的情况,例如下载视频图片的情况,特别是云服务器会有带宽限制,超出带宽会出现掉包丢数据的情况,例如:云服务器限制25m/s的速度,当一个视频下载超过25m/s的速度的时候就会导致掉包,除了限速还需要注意下并发问题,多个线程同时下载也会超出带宽限制,可实现该代码并设置单独的线程池,控制同时并发的线程数来解决带宽问题.
逻辑:
我们可以使用一个缓冲区,每次从输入流读取数据后,先将写入文件的同时更新MD5,这样更高效,因为只需要处理一次数据。这样就不会增加额外的读取次数,避免影响性能。然后,带宽限流的逻辑需要确保在限流的同时处理这两个操作。每次读取数据块后,会计算总字节数和时间,判断是否需要暂停(使用Thread.sleep())。计算MD5的消耗应该相对较小,主要的时间还是在网络读取和文件写入上。
1. 核心公式
限速逻辑基于以下公式实现:
预期耗时(ms)=已下载总字节数×1000最大允许带宽(B/s)预期耗时(ms)=最大允许带宽(B/s)已下载总字节数×1000

其中 MAX_BPS = NMB/s = N × 1024 × 1024 B/s
2. 控制逻辑分步说明
| 步骤 | 代码片段 | 说明 |
|---|---|---|
| 1. 记录开始时间 | long startTime = System.currentTimeMillis(); | 下载任务启动时记录初始时间戳 |
| 2. 累计下载量 | totalBytes += bytesRead; | 每次读取数据块后更新总字节数 |
| 3. 计算理论耗时 | expectedTime = (totalBytes * 1000) / MAX_BPS | 根据当前下载量计算理论应耗时 |
| 4. 对比实际耗时 | elapsed = now - startTime | 获取实际已耗时 |
| 5. 动态休眠补偿 | Thread.sleep(expectedTime - elapsed) | 强制等待至理论时间线 |
流程:
1. 打开网络连接,获取输入流。
2. 创建文件输出流和MessageDigest实例。
3. 循环读取数据到缓冲区,每次读取后写入文件,更新MD5(MD5可以边读取文件边计算,防止整个文件读取完再计算导致的内存压力),并进行限流计算。
4. 下载完成后,关闭流,并输出MD5结果。
实现:
public static String getMd5(String url, String type) {
CloseableHttpClient httpClient = HttpClients.createDefault();
final long MAX_BPS = 2 * 1024 * 1024; // 200Mbps = 25MB/s
MessageDigest md;
// 创建时间格式化器(线程安全)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 algorithm not found", e);
}
try (CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {
HttpEntity entity = response.getEntity();
if (entity == null) {
return "";
}
// 记录开始时间
long startTime = System.currentTimeMillis();
try (InputStream in = entity.getContent()) {
byte[] buffer = new byte[8192];
int bytesRead;
long totalBytes = 0;
while ((bytesRead = in.read(buffer)) != -1) {
md.update(buffer, 0, bytesRead);
totalBytes += bytesRead;
// 动态限速逻辑
long elapsed = System.currentTimeMillis() - startTime;
long expectedTime = (totalBytes * 1000) / MAX_BPS;
if (elapsed < expectedTime) {
Thread.sleep(expectedTime - elapsed);
}
}
// 计算最终统计信息
long endTime = System.currentTimeMillis();
double timeCost = DoubleUtils.formatDouble((endTime - startTime) / 1000.0);
String sizeMB = String.format("%.3f", DoubleUtils.formatDouble(totalBytes / (1024.0 * 1024)));
// 生成MD5
String md5 = DatatypeConverter.printHexBinary(md.digest()).toLowerCase();
// 完整日志输出
log.info("下载完成 | 类型: {} | MD5: {} | 大小: {}MB | 耗时: {}s",
type, md5, sizeMB, timeCost);
return md5;
}
} catch (Exception e) {
// 记录异常发生时间
String errorTime = LocalDateTime.now().format(formatter);
log.error("下载失败 | 类型: {} | 错误时间: {} | 原因: {}",
type, errorTime, e.getMessage());
return "";
}finally {
try {
httpClient.close();
}catch (Exception e) {
}
}
}到此这篇关于Java实现http请求文件流对带宽限速获取md5值的文章就介绍到这了,更多相关java带宽限速获取md5值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
MyBatis Generator ORM层面的代码自动生成器(推荐)
Mybatis Generator是一个专门为 MyBatis和 ibatis框架使用者提供的代码生成器,也可以快速的根据数据表生成对应的pojo类、Mapper接口、Mapper文件,甚至生成QBC风格的查询对象,这篇文章主要介绍了MyBatis Generator ORM层面的代码自动生成器,需要的朋友可以参考下2023-01-01
SpringCloud-Gateway转发WebSocket失败问题及解决
这篇文章主要介绍了SpringCloud-Gateway转发WebSocket失败问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2023-09-09
兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil
今天小编就为大家分享一篇关于兼容Spring Boot 1.x和2.x配置类参数绑定的工具类SpringBootBindUtil,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧2018-12-12
基于java springboot + mybatis实现电影售票管理系统
这篇文章主要介绍了基于java springboot + mybatis实现的完整电影售票管理系统基于java springboot + mybatis,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-08-08
SpringBoot整合Security实现权限控制框架(案例详解)
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框,是一个重量级的安全管理框架,本文给大家介绍的非常详细,需要的朋友参考下吧2021-08-08


最新评论