Java限速器,设计思路
1.假设下载或上传速度上限是: m(KB/s),那么发送一个固定的字节数据[假设是n字节(Bytes)]
时间花费 -> 单位:毫秒 == 1000 * n/(m*1024)
2.假设发送n字节的数据只花费了t毫秒,
那么发送线程就应该睡眠(毫秒): 1000 * n/(m*1024)- t毫秒
java实现代码
public class SpeedLimiter {
/** 速度上限(KB/s), 0=不限速 */
private int maxRate = 1024;
private long getMaxRateBytes(){
return this.maxRate * 1024;
}
private long getLessCountBytes() {
long lcb = getMaxRateBytes() / 10;
if (lcb < 10240) lcb = 10240;
return lcb;
//return 1024l * 20;
}
public SpeedLimiter(int maxRate) {
this.setMaxRate(maxRate);
}
public synchronized void setMaxRate(int maxRate){
this.maxRate = maxRate < 0 ? 0 : maxRate;
}
private long totalBytes = 0;
private long tmpCountBytes = 0;
private long lastTime = System.currentTimeMillis();
/**
* @author Ethan
* @date 2022-11-18
* @param len send bytes
* @description 计算线程延时
* sendTime(Ms) = nowTime - lastTime;
* workTime(Ms) = (totalBytes*1000)/(maxRate*1024)
* delayTime(Ms) = workTime-sendTime
**/
public synchronized void delayNextBytes(int len) {
if (maxRate <= 0) return;
totalBytes += len;
tmpCountBytes += len;
//未达到指定字节数跳过...
if (tmpCountBytes < getLessCountBytes()) {
return;
}
long nowTime = System.currentTimeMillis();
long sendTime = nowTime - lastTime;
long workTime = (totalBytes * 1000) / getMaxRateBytes();
long delayTime = workTime - sendTime;
if (delayTime > 0) {
try {
Thread.sleep(delayTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmpCountBytes = 0;
}
}
}
集成到Springboot进行下载测试
DownloadController代码
@RestController
@RequestMapping(value = "/api/v1/download")
public class DownloadController {
//设置一个本地文件用于下载测试, 大小约几百MB
final String localFile = "E:/tmp/A2.tar.gz";
/**
* @author Ethan
* @date 2022-11-18
* @description 普通下载测试, 不限速!
**/
@GetMapping("getFile")
public void getFile(HttpServletResponse response) {
File file = this.getLocalFile(response, localFile);
if (file == null || !file.exists()) {
return;
}
InputStream is = null;
OutputStream out = null;
try {
is = new FileInputStream(file);
out = response.getOutputStream();
IOUtils.copyLarge(is, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(out);
}
}
/**
* @author Ethan
* @date 2022-11-18
* @description 限速下载测试, xxx KB/s
**/
@GetMapping("limit")
public void limit(
@RequestParam(value = "speed", defaultValue = "500", required = false) int speed,
HttpServletResponse response
) {
File file = this.getLocalFile(response, localFile);
if (file == null || !file.exists()) {
return;
}
BufferedInputStream bis = null;
OutputStream out = null;
try {
bis = new BufferedInputStream(new FileInputStream(file));
out = response.getOutputStream();
byte[] buffer = new byte[1024];
int length;
SpeedLimiter speedLimiter = new SpeedLimiter(speed);
while ((length = bis.read(buffer)) != -1) {
out.write(buffer, 0, length);
if (speedLimiter != null) {
speedLimiter.delayNextBytes(length);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(bis);
IOUtils.closeQuietly(out);
}
}
private File getLocalFile(HttpServletResponse response, String fullPath){
File file = new File(fullPath);
if (file.exists()) {
String fileName = file.getName();
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Type", "application/x-zip-compressed");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
} else {
String noteMsg = "本地测试文件[" + file + "]不存在";
System.err.println(noteMsg);
this.setResponse(response, noteMsg);
}
return file;
}
private final static String CharacterEncoding = "UTF-8";
private final static String MediaType = "application/json";
private void setResponse(HttpServletResponse res, String noteMsg) {
try {
int httpStatus = HttpStatus.OK.value();
res.setCharacterEncoding(CharacterEncoding);
res.setContentType(MediaType);
res.setStatus(httpStatus);
res.getWriter().write(noteMsg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
启动Springboot
使用firefox浏览器分别测试
限速下载(500KB/s) http://127.0.0.1:8080/api/v1/download/limit
限速下载(900KB/s) http://127.0.0.1:8080/api/v1/download/limit?speed=900
经过测试,可以满足需求!
完整demo下载地址
https://download.csdn.net/download/tianbbs2008/87126141
版权声明:本文为tianbbs2008原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。