美文网首页
Android 性能优化01 --- 网络优化01(链接复用)

Android 性能优化01 --- 网络优化01(链接复用)

作者: 沪漂意哥哥 | 来源:发表于2022-03-30 23:31 被阅读0次

一. 链路不复用的情况

 public String get(String requestUrl) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(requestUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(60000);
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.connect();
            Map<String, List<String>> map = connection.getHeaderFields();
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                StringBuffer sbf = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sbf.append(line);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != br) {
                    br.close();
                }
                if (null != is) {
                    is.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            connection.disconnect();
        }
        return result;
    }

 public void getMore(View view) {
        new Thread() {
            @Override
            public void run() {
                final long start = System.currentTimeMillis();
                for (int i = 0; i < 10; i++) {
                    String data= get("http://www.kuaidi100.com/query?type=yuantong&postid=222222222");
                    Log.i("liuyi", "data: "+data);
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_time.setText("耗费时间: " +( System.currentTimeMillis() - start));
                    }
                });

            }
        }.start();
    } 
执行结果: image.png

二. 链路复用的情况

 public void get(View view) {
        new Thread() {
            @Override
            public void run() {
                final long start = System.currentTimeMillis();
                for (int i = 0; i < 10; i++) {
                    HttpUrl httpUrl = new HttpUrl("http://www.kuaidi100.com/query?type=yuantong&postid=222222222");
                    Request request = new Request();
                    request.setHttpUrl(httpUrl);
                    String data = netUtil.call(request);
                    Log.i("liuyi", "data: "+data);
                }

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_time.setText("耗费时间: " +( System.currentTimeMillis() - start));
                    }
                });

            }
        }.start();
    }
执行结果: image.png

三. NetUtil

 public class NetUtil {
    private ConnectionPool connectionPool;
    public NetUtil() {
        connectionPool = new ConnectionPool();
    }

    public String call(Request request) {
        HttpConnection httpConnection= connectionPool.getHttpConnection(request.getHttpUrl().getHost(),
                request.getHttpUrl().getPort());
        httpConnection.setHttpUrl(request.getHttpUrl());
        String body = httpConnection.call(request);
        //服务器 复用
        if (httpConnection.isKeepAlive()) {
            connectionPool.putHttpConnection(httpConnection);
        } else {
            httpConnection.close();
        }
        return body;
    }
}

四. ConnectionPool

 public class ConnectionPool {
    private Deque<HttpConnection> httpConnections = new ArrayDeque<>();

    public void putHttpConnection(HttpConnection httpConnection){
        httpConnections.add(httpConnection);
    }

    public synchronized HttpConnection getHttpConnection(String host, int port) {
        Iterator<HttpConnection> httpConnectionIterator = httpConnections.iterator();
        HttpConnection httpConnection = null;
        while(httpConnectionIterator.hasNext()){
            httpConnection = httpConnectionIterator.next();
            if (httpConnection.isSameAddress(host, port)) {
                httpConnectionIterator.remove();
                break;
            }
        }
        if (null == httpConnection) {
            httpConnection = new HttpConnection();
        } else {
            Log.d("liuyi", "从连接池中获得连接");
        }
        return httpConnection;
    }
}


五. HttpConnection

 public class HttpConnection {
    private InputStream inputStream;
    private OutputStream outputStream;
    Socket socket;
    HttpUrl httpUrl;
    HttpCodec httpCodec = new HttpCodec();
    public void setHttpUrl(HttpUrl httpUrl) {
        this.httpUrl = httpUrl;
    }

    public boolean isSameAddress(String host, int port){
        if(null == socket){
            return false;
        }
        return TextUtils.equals(httpUrl.getHost(),host) && httpUrl.port == port;
    }

    private void createSocket() throws IOException {
        if (null == socket || socket.isClosed()) {
            if (httpUrl.protocol.equalsIgnoreCase("https")) {
                socket = SSLSocketFactory.getDefault().createSocket();
            } else {
                socket = new Socket();
            }
            socket.connect(new InetSocketAddress(httpUrl.getHost(), httpUrl.getPort()));
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
        }
    }

    public void close(){
        if(null != socket){
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String call(Request request) {
        try {
            createSocket();
        } catch (IOException e) {
            e.printStackTrace();
        }
        httpCodec.writeRequest(outputStream, request);
        return parseBody();
    }

    String statusLine;
    Map<String, String> headers;
    public boolean isKeepAlive( ){
        String[] status = statusLine.split(" ");
        boolean isKeepAlive = false;
        if(headers.containsKey("Connection")){
            isKeepAlive = headers.get("Connection").equalsIgnoreCase("Keep-Alive");
        }
        return isKeepAlive;
    }

    public String parseBody( )  {
        String body = null;
        try {
            statusLine =httpCodec.readLine(inputStream);
            //获取服务器返回的响应头
            headers = httpCodec.readHeaders(inputStream);
            int contentLength = -1;
            if(headers.containsKey("Content-Length")){
                contentLength = Integer.valueOf(headers.get("Content-Length"));
            }
            if(contentLength > 0){
                byte[] bodyBytes = httpCodec.readBytes(inputStream,contentLength);
                body = new String(bodyBytes,"UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return body ;
    }

}

六. HttpUrl

 public class HttpUrl {
    public String file;
    public String protocol;
    public int port;
    public String host;
    public HttpUrl(String url) {
        try {
            URL localUrl = new URL(url);//url格式化
            host = localUrl.getHost();
            protocol = localUrl.getProtocol();
            port = localUrl.getPort();
            file = localUrl.getFile();
            if (port == -1) {
                //代表url中没有端口信息,就是使用默认端口,http:80,https:443
                port = localUrl.getDefaultPort();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }
}


七. HttpCodec

 public class HttpCodec {
    static final String SPACE = " ";//一个空格
    static final String HTTP_VERSION = "HTTP/1.1";//http的版本信息
    static final String COLON = ":";//冒号
    static final String CRLF = "\r\n";
    //http响应中 13 http结束
    static final int CR = 13;
    static final int LF = 10;//换行的ASCII码
    private ByteBuffer byteBuffer;
    public HttpCodec(){
        byteBuffer = ByteBuffer.allocate(10 * 1024);
    }

    public void writeRequest(OutputStream os, Request request) {
        StringBuffer sb = new StringBuffer();
        sb.append(request.getMethod());
        sb.append(SPACE);
        sb.append(request.getHttpUrl().file);
        sb.append(SPACE);//一个空格
        sb.append(HTTP_VERSION);// HTTP/1.1
        sb.append("\r\n");//一个回车换行
        Map<String, String> headers = request.getHeaders();
        for(Map.Entry<String, String> entry : headers.entrySet()){
            sb.append(entry.getKey());
            sb.append(COLON);//一个冒号
            sb.append(SPACE);//一个空格
            sb.append(entry.getValue());
            sb.append(CRLF);//最后面跟一个回车和换行
        }
        sb.append(CRLF);//最后面跟一个回车和换行
        try {
            os.write(sb.toString().getBytes());
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean isEmptyLine(String line){
        return TextUtils.equals(line,CRLF);
    }

    public byte[] readBytes(InputStream is, int length) throws IOException {
        byte[] bytes = new byte[length];
        int readNum = 0;
        while(true){
            readNum = is.read(bytes,readNum,length - readNum);
            if(readNum == length){
                return bytes;
            }
        }
    }
    public Map<String, String> readHeaders(InputStream is) throws IOException {
        HashMap<String, String> headers = new HashMap<>();
        while(true) {
            String line = null;
            try {
                line = readLine(is);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (isEmptyLine(line)) {
                //如果读到空行 \r\n 响应头读完了
                break;
            }
            int index = line.indexOf(":");//因为服务器返回的响应头中的格式也是key: value的格式
            if (index > 0) {
                String key = line.substring(0, index);
                //这里加2 是因为,value前面还有冒号和空格,所以,value的第一个位置,需要往后移

                //减2是因为line后面有/r/n两个字节
                String value = line.substring(index + 2, line.length() - 2);
                headers.put(key, value);
            }
        }
        return headers;
    }

    public String readLine(InputStream is) throws Exception {
        byteBuffer.clear();
        byteBuffer.mark();
        byte b;
        boolean isMaybeEofLine = false;
        while((b = (byte)is.read()) != -1){
            byteBuffer.put(b);
            if(b == CR) {//如果读到一个 /r
                isMaybeEofLine = true;

            }
            if (isMaybeEofLine) {
                if(b == LF) {//如果读到一个 /n了,意味着,行结束了
                    byte[] lineBytes = new byte[byteBuffer.position()];//new一个一行数据大小的字节数据
                    byteBuffer.reset();
                    byteBuffer.get(lineBytes);
                    byteBuffer.clear();//清空
                    byteBuffer.mark();
                    return new String(lineBytes, "UTF-8");
                }
            }
        }
        return "";
    }

}


八. Request

 public class Request {
    public static final String HEAD_HOST = "Host";
    public static final String HEAD_CONNECTION = "Connection";
    public static final String HEAD_VALUE_KEEP_ALIVE = "Keep-Alive";

    private String method = "GET";
    private HttpUrl httpUrl = null;
    public HttpUrl getHttpUrl() {
        return httpUrl;
    }

    public void setHttpUrl(HttpUrl httpUrl) {
        this.httpUrl = httpUrl;
        Map<String, String> tempHeaders = getHeaders();
        if (!tempHeaders.containsKey(HEAD_HOST)) {
            tempHeaders.put(HEAD_HOST,getHttpUrl().getHost());
        }
        if(!tempHeaders.containsKey(HEAD_CONNECTION)) {
            tempHeaders.put(HEAD_CONNECTION, HEAD_VALUE_KEEP_ALIVE);
        }
    }

    Map<String, String> headers = new HashMap<>();

    public String getMethod() {
        return method;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

}


八. 代码地址

https://gitee.com/luisliuyi/android-optimize-network01.git

相关文章

网友评论

      本文标题:Android 性能优化01 --- 网络优化01(链接复用)

      本文链接:https://www.haomeiwen.com/subject/jghgjrtx.html