需求: 因为工作站网络上行带宽过高会影响其他服务的正常使用,所以要限速
HttpClient.java
package com.wuchen.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wuchen.constant.Constant;
import com.wuchen.servlet.LimitRateFileBody;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import java.io.File;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
public class HttpClient {
private static Integer socketTime = null;
private static Integer connectTime = null;
private static Integer connectionRequestTime = null;
private static Logger logger = Logger.getLogger(HttpClient.class);
private static String token = null;
public static JSONObject doPost(JSONObject params, String url) {
if (socketTime == null) {
Properties properties = new PropertiesUtil().readPropertiesFile("application.properties");
socketTime = Integer.valueOf(properties.getProperty("socketTime"));
connectTime = Integer.valueOf(properties.getProperty("connectTime"));
connectionRequestTime = Integer.valueOf(properties.getProperty("connectionRequestTime"));
}
org.apache.http.client.HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(url);
try {
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
httpPost.setHeader("Connection", "Close");
StringEntity entity = new StringEntity(params.toString(), Charset.forName("UTF-8"));
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost);
String resultString = EntityUtils.toString(response.getEntity());
JSONObject rempResult = JSON.parseObject(resultString);
return rempResult;
} catch (Exception e) {
logger.error("error", e);
return null;
}
}
public static JSONObject postFrom(JSONObject params, List paths, String url) {
org.apache.http.client.HttpClient httpClient = HttpClientBuilder.create().build();
try {
HttpPost httpPost = new HttpPost(url);
StringBody comment = new StringBody(params.toString(), ContentType.TEXT_PLAIN);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
for (String filePath : paths) {
multipartEntityBuilder.addPart("file", new FileBody(new File(filePath)));
}
HttpEntity reqEntity = multipartEntityBuilder.addPart("desc", comment).build();
httpPost.setEntity(reqEntity);
HttpResponse response = httpClient.execute(httpPost);
String resultString = EntityUtils.toString(response.getEntity());
JSONObject result = JSON.parseObject(resultString);
return result;
} catch (Exception e) {
logger.error("error", e);
return null;
}
}
public static JSONObject postFromListRate(JSONObject params, List paths, String url) {
org.apache.http.client.HttpClient httpClient = HttpClientBuilder.create().build();
try {
HttpPost httpPost = new HttpPost(url);
StringBody comment = new StringBody(params.toString(), ContentType.TEXT_PLAIN);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
for (String filePath : paths) {
multipartEntityBuilder.addPart("file", new LimitRateFileBody(new File(filePath), params.getInteger(Constant.MAX_RATE)));
}
HttpEntity reqEntity = multipartEntityBuilder.addPart("desc", comment).build();
httpPost.setEntity(reqEntity);
HttpResponse response = httpClient.execute(httpPost);
String resultString = EntityUtils.toString(response.getEntity());
JSONObject result = JSON.parseObject(resultString);
return result;
} catch (Exception e) {
logger.error("error", e);
return null;
}
}
}
LimitRateBody.java
package com.wuchen.servlet;
import com.wuchen.utils.BandwidthLimiter;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.util.Args;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author: WangXiang
* @date: 2020/4/28 0028
**/
public class LimitRateFileBody extends FileBody {
private final File file;
private final String filename;
//限速的大小
private int maxRate = 1024;
public LimitRateFileBody(File file, int maxRate) {
this(file, ContentType.DEFAULT_BINARY, file != null ? file.getName() : null);
this.maxRate = maxRate;
}
public LimitRateFileBody(File file) {
this(file, ContentType.DEFAULT_BINARY, file != null ? file.getName() : null);
}
public LimitRateFileBody(File file, ContentType contentType, String filename) {
super(file, contentType, filename);
this.file = file;
this.filename = filename;
}
public LimitRateFileBody(File file, ContentType contentType) {
this(file, contentType, file != null ? file.getName() : null);
}
@Override
public void writeTo(OutputStream out) throws IOException {
Args.notNull(out, "Output stream");
FileInputStream in = new FileInputStream(this.file);
LimitInputStream ls = new LimitInputStream(in, new BandwidthLimiter(this.maxRate));
try {
byte[] tmp = new byte[4096];
int l;
while ((l = ls.read(tmp)) != -1) {
out.write(tmp, 0, l);
}
out.flush();
} finally {
in.close();
}
}
public void setMaxRate(int maxRate) {
this.maxRate = maxRate;
}
}
LimitInputStream.java
package com.wuchen.servlet;
import com.wuchen.utils.BandwidthLimiter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 限流文件读取
*
* @author: WangXiang
* @date: 2019/12/20 0020
**/
public class LimitInputStream extends InputStream {
private InputStream inputStream;
private BandwidthLimiter bandwidthLimiter;
public LimitInputStream(InputStream inputStream, BandwidthLimiter bandwidthLimiter) {
this.inputStream = inputStream;
this.bandwidthLimiter = bandwidthLimiter;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (bandwidthLimiter != null) {
bandwidthLimiter.limitNextBytes(len);
}
return inputStream.read(b, off, len);
}
@Override
public int read(byte[] b) throws IOException {
if (bandwidthLimiter != null && b.length > 0) {
bandwidthLimiter.limitNextBytes(b.length);
}
return inputStream.read(b);
}
@Override
public int read() throws IOException {
if (bandwidthLimiter != null) {
bandwidthLimiter.limitNextBytes();
}
return inputStream.read();
}
}
BandwidthLimiter.java
package com.wuchen.utils;
import com.wuchen.service.FileUploadService;
import org.apache.log4j.Logger;
/**
* @author: WangXiang
* @date: 2019/12/20 0020
**/
public class BandwidthLimiter {
private static Logger logger = Logger.getLogger(BandwidthLimiter.class);
//KB代表的字节数
private static final Long KB = 1024L;
//一个chunk的大小,单位byte。设置一个块的大小为1M
private static final Long CHUNK_LENGTH = 1024 * 1024L;
//已经发送/读取的字节数
private int bytesWillBeSentOrReceive = 0;
//上一次接收到字节流的时间戳——单位纳秒
private long lastPieceSentOrReceiveTick = System.nanoTime();
//允许的最大速率,默认为 1024KB/s
private int maxRate = 1024;
//在maxRate的速率下,通过chunk大小的字节流要多少时间(纳秒)
private long timeCostPerChunk = (1000000000L * CHUNK_LENGTH) / (this.maxRate * KB);
public BandwidthLimiter(int maxRate) {
this.setMaxRate(maxRate);
}
//动态调整最大速率
public void setMaxRate(int maxRate) {
if (maxRate < 0) {
throw new IllegalArgumentException("maxRate can not less than 0");
}
this.maxRate = maxRate;
if (maxRate == 0) {
this.timeCostPerChunk = 0;
} else {
this.timeCostPerChunk = (1000000000L * CHUNK_LENGTH) / (this.maxRate * KB);
}
}
public synchronized void limitNextBytes() {
this.limitNextBytes(1);
}
public synchronized void limitNextBytes(int len) {
this.bytesWillBeSentOrReceive += len;
while (this.bytesWillBeSentOrReceive > CHUNK_LENGTH) {
long nowTick = System.nanoTime();
long passTime = nowTick - this.lastPieceSentOrReceiveTick;
long missedTime = this.timeCostPerChunk - passTime;
if (missedTime > 0) {
try {
Thread.sleep(missedTime / 1000000, (int) (missedTime % 1000000));
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
this.bytesWillBeSentOrReceive -= CHUNK_LENGTH;
this.lastPieceSentOrReceiveTick = nowTick + (missedTime > 0 ? missedTime : 0);
}
}
}