Servlet IO限速的一种粗略实现

来源:互联网 发布:unity3d 机械仿真 编辑:程序博客网 时间:2024/04/29 13:56

本实现参考了 Daniel Matuschek - A FilterInputStream with a limited bandwith

分别为设置下载限制速度为1MB/s 128KB/s 256KB/s,使用wget测试下载速度
测试结果如图:
这里写图片描述

代码如下:

package com.bimwinner.commons.web.filter;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.StringTokenizer;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ReadListener;import javax.servlet.ServletException;import javax.servlet.ServletInputStream;import javax.servlet.ServletOutputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletRequestWrapper;import javax.servlet.ServletResponse;import javax.servlet.ServletResponseWrapper;import javax.servlet.WriteListener;import javax.servlet.annotation.WebFilter;import javax.servlet.annotation.WebInitParam;/** * Simple QoS limit filter * <b>Note: </b> * input limit works only when <code>request.getInputStream()</code> was invoked; * (e.g. form-data upload don't, binary upload do)<br/> * output limit works only when <code>response.getOutputStream()</code> was invoked; * (e.g. jsp html don't, servlet download do) * @author Fuwei Chin */@WebFilter(filterName="QoS",initParams={        @WebInitParam(name="outputLimit",value="1*1024*1024")})public class QoSFilter implements Filter {    private int inputLimit=-1;    private int outputLimit=-1;    @Override    public void init(FilterConfig filterConfig) throws ServletException {        Double inputLimit=eval(filterConfig.getInitParameter("inputLimit"));        if(inputLimit!=null){            this.inputLimit=inputLimit.intValue();        }        Double outputLimit=eval(filterConfig.getInitParameter("outputLimit"));        if(outputLimit!=null){            this.outputLimit=outputLimit.intValue();        }    }    @Override    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)            throws IOException, ServletException {        chain.doFilter(inputLimit<=0?req:new QoSServletRequestWrapper(req,inputLimit),                 outputLimit<=0?res:new QoSServletResponseWrapper(res,outputLimit));    }    @Override    public void destroy() {    }    private static Double eval(String expr){        if(expr==null){            return null;        }        List<Double> values=new ArrayList<>();        StringTokenizer st=new StringTokenizer(expr, "*");        while(st.hasMoreTokens()){            values.add(Double.parseDouble(st.nextToken()));        }        if(values.size()>0){            double result=1d;            for(Double i:values){                result*=i;            }            return result;        }        return null;    }}class QoSServletRequestWrapper extends ServletRequestWrapper {    private int limit;    private ServletInputStream in;    public QoSServletRequestWrapper(ServletRequest request,int limit) {        super(request);        this.limit=limit;    }    @Override    public ServletInputStream getInputStream() throws IOException {        if(in==null){            in=new QosServletInputStream(super.getInputStream(), this.limit);        }        return in;    }}class QoSServletResponseWrapper extends ServletResponseWrapper {    private int limit;    private ServletOutputStream out;    public QoSServletResponseWrapper(ServletResponse response,int limit) {        super(response);        this.limit=limit;    }    @Override    public ServletOutputStream getOutputStream() throws IOException {        if(out==null){            out=new QoSServletOutputStream(super.getOutputStream(), this.limit);        }        return out;    }}class QosServletInputStream extends ServletInputStream {    private ServletInputStream in;    private int limit;    private int read;    private long startTime;    public QosServletInputStream(ServletInputStream in,int limit) {        this.in=in;        this.limit=limit;    }    @Override    public int read() throws IOException {        int r=in.read();        if(r!=-1&&(this.read+=1)>limit){            checkSpeed();        }        return r;    }    @Override    public int read(byte[] b) throws IOException {        return this.read(b,0,b.length);    }    @Override    public int read(byte[] b, int off, int len) throws IOException {        int r=in.read(b, off, len);        if(r!=-1&&(this.read+=r)>limit){            checkSpeed();        }        return r;    }    @Override    public long skip(long n) throws IOException {        return in.skip(n);    }    @Override    public int available() throws IOException {        return in.available();    }    @Override    public synchronized void mark(int readlimit) {        in.mark(readlimit);    }    @Override    public synchronized void reset() throws IOException {        in.reset();    }    @Override    public boolean markSupported() {        return in.markSupported();    }    @Override    public void close() throws IOException {        in.close();    }    @Override    public boolean isFinished() {        return in.isFinished();    }    @Override    public boolean isReady() {        return in.isReady();    }    @Override    public void setReadListener(ReadListener listener) {        in.setReadListener(listener);    }    private void checkSpeed(){        long elapsedTime=System.currentTimeMillis()-startTime;        long sleepTime=1000-elapsedTime;        if(sleepTime>0){            try {                System.out.println("sleep "+sleepTime);                Thread.sleep(sleepTime);            } catch (InterruptedException e) {            }        }        this.read=0;        this.startTime=System.currentTimeMillis();    }}class QoSServletOutputStream extends ServletOutputStream {    private ServletOutputStream out;    private int limit;    private int written;    private long startTime;    public QoSServletOutputStream(ServletOutputStream out,int limit) {        this.out=out;        this.limit=limit;    }    @Override    public void write(int b) throws IOException {        out.write(b);        if((this.written+=1)>limit){            checkSpeed();        }    }    @Override    public void write(byte[] b) throws IOException {        this.write(b, 0, b.length);    }    @Override    public void write(byte[] b, int off, int len) throws IOException {        out.write(b, off, len);        if((this.written+=len)>limit){            checkSpeed();        }    }    @Override    public void flush() throws IOException {        out.flush();    }    @Override    public void close() throws IOException {        out.close();    }    @Override    public boolean isReady() {        return out.isReady();    }    @Override    public void setWriteListener(WriteListener listener) {        out.setWriteListener(listener);    }    private void checkSpeed(){        long elapsedTime=System.currentTimeMillis()-startTime;        long sleepTime=1000-elapsedTime;        if(sleepTime>0){            try {                Thread.sleep(sleepTime);            } catch (InterruptedException e) {            }        }        this.written=0;        this.startTime=System.currentTimeMillis();    }}
原创粉丝点击