使用Socket请求网络

主要使用Socket请求网络,并完成响应行、响应体、响应头的输出
先看结果

响应行 = HTTP/1.1 200 OK

响应头
key = Transfer-Encoding, value = chunked
key = Server, value = nginx
key = Cache-Control, value = no-cache
key = Connection, value = keep-alive
key = Vary, value = Accept-Encoding
key = P3P, value = CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
key = Date, value = Sun, 05 Aug 2018 09:45:41 GMT
key = Content-Type, value = text/html;charset=UTF-8
响应体 = {"message":"ok","nu":"111111","ischeck":"0","condition":"B00","com":"yuantong","status":"200","state":"1","data":[{"time":"2016-01-20 21:35:35","ftime":"2016-01-20 21:35:35","context":"上海市闵行区莘庄公司(13585705701)已收件","location":null}]}
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

public class MyClass {
    public static void main(String[] args) throws IOException {
        String path = "http://www.kuaidi100.com/query?type=yuantong&postid=111111";
//        String path = "http://www.baidu.com/";

        HttpUrl httpUrl = new HttpUrl(path);
        Request request = new Request.Builder()
                .url(httpUrl)
                .addHeader("Host", httpUrl.getHost())
                .addHeader("Connection", "keep-alive")
                .build();
        HttpConnection httpConnection = new HttpConnection(request);
        HttpCodec httpCodec = new HttpCodec();
        InputStream is = httpConnection.call(httpCodec);
        //读取响应行
        String responseLine = httpCodec.readLine(is);
        System.out.println("responseLine = " + responseLine);
        //读取响应头
        Map<String, String> headers = httpCodec.readHeaders(is);
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
        }
        //响应头分为两种,一种带有Content-Length,会告诉你响应体后面有多少个字节
        //一种是Transfer-Encoding:chunked
        //会将响应体分成好几段
        //例如
        //\r\n 响应头和响应体之间的间隔
        //10\r\n
        //10个字节长度的数据\r\n
        //15\r\n
        //15个字节长度的数据\r\n
        //0\r\n  结束
        //\r\n

        //读取响应体
        int contentLength = -1;
        if (headers.containsKey("Content-Length")) {
            contentLength = Integer.valueOf(headers.get("Content-Length"));
        }
        boolean isChunked = false;
        if (headers.containsKey("Transfer-Encoding")) {
            isChunked = headers.get("Transfer-Encoding").equalsIgnoreCase("chunked");
        }
        if (contentLength > 0) {
            byte[] bytes = httpCodec.readBody(is, contentLength);
            System.out.println("Response = " + new String(bytes));
        }else if (isChunked) {
            String s = httpCodec.readChunked(is);
            System.out.println("Response = " + s);
        }
    }
}

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

class HttpCodec {

    private final ByteBuffer byteBuffer;

    public HttpCodec() {
        byteBuffer = ByteBuffer.allocate(10 * 1024);
    }

    /**
     * 发送请求 拼接请求行、请求头
     *
     * @param os      输出流
     * @param request 请求参数
     * @throws IOException
     */
    public void writeRequest(OutputStream os, Request request) throws IOException {
        HttpUrl url = request.url();
        StringBuffer sb = new StringBuffer();
        //拼接请求行
        sb.append(request.method());
        sb.append(" ");
        sb.append(url.getFile());
        sb.append(" ");
        sb.append("HTTP/1.1\r\n");
        //请求头
        Map<String, String> headers = request.headers();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            sb.append(entry.getKey());
            sb.append(": ");
            sb.append(entry.getValue());
            sb.append("\r\n");
        }
        sb.append("\r\n");
        os.write(sb.toString().getBytes("UTF-8"));
        os.flush();
    }

    public String readLine(InputStream is) throws IOException {
        byte b;
        byteBuffer.clear();
        byteBuffer.mark();
        //可能读取到一行了
        boolean isMabeyEofLine = false;
        while ((b = (byte) is.read()) != -1) {
            byteBuffer.put(b);
            if (b == 13) {
                isMabeyEofLine = true;
            } else if (isMabeyEofLine) {
                //读取到了/n
                if (b == 10) {
                    //获得一行数据
                    byte[] lineBytes = new byte[byteBuffer.position()];
                    byteBuffer.reset();
                    byteBuffer.get(lineBytes);
                    byteBuffer.clear();
                    byteBuffer.mark();
                    String line = new String(lineBytes);
                    return line;
                } else {
                    isMabeyEofLine = false;
                }
            }
        }
        return null;
    }

    /**
     * 读取响应头
     *
     * @param is
     * @return
     * @throws IOException
     */
    public Map<String, String> readHeaders(InputStream is) throws IOException {
        HashMap<String, String> headers = new HashMap<>();
        while (true) {
            String line = readLine(is);
            if (line.equals("\r\n")) {//因为响应头和响应体中间隔了个"\r\n"
                break;
            }
            int index = line.indexOf(":");
            if (index > 0) {
                String name = line.substring(0, index);
                String value = line.substring(index + 2, line.length() - 2);
                headers.put(name, value);
            }
        }
        return headers;
    }

    public byte[] readBody(InputStream is, int len) throws IOException {
        byte[] bytes = new byte[len];
        int readNum = 0;
        while (true) {
            readNum += is.read(bytes);
            if (readNum == len) {
                return bytes;
            }
        }
    }

    public String readChunked(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        int len = -1;
        boolean isEmptyData = false;
        while (true) {
            if (len < 0) {
                String line = readLine(is);
                line = line.substring(0, line.length() - 2);//\r\n
                len = Integer.valueOf(line, 16);
                isEmptyData = len == 0;
            } else {
                byte[] bytes = readBody(is, len + 2);
                sb.append(new String(bytes));
                len = -1;
                if (isEmptyData) {
                    return sb.toString();
                }
            }
        }
    }
}

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import javax.net.ssl.SSLSocketFactory;


public class HttpConnection {
    private Request request;
    private Socket socket;
    private InputStream is;
    private OutputStream os;

    public HttpConnection(Request request) {
        this.request = request;
    }

    /**
     * 连接Socket
     */
    public InputStream call(HttpCodec httpCodec) throws IOException {
        createSocket();
        //发送请求
        httpCodec.writeRequest(os, request);
        return is;
    }

    public void createSocket() throws IOException {
        if (socket != null) {
            return;
        }
        HttpUrl url = request.url();
        if (url.getProtocol().equalsIgnoreCase("https")) {
            socket = SSLSocketFactory.getDefault().createSocket();
        } else {
            socket = new Socket();
        }
        //连接服务器
        socket.connect(new InetSocketAddress(url.getHost(), url.getPort()));
        is = socket.getInputStream();
        os = socket.getOutputStream();
    }
}

import java.net.MalformedURLException;
import java.net.URL;


public class HttpUrl {

    private String file;
    private int port;
    private final String protocol;
    private final String host;

    public String getFile() {
        return file;
    }

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

    public int getPort() {
        return port;
    }

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

    public String getProtocol() {
        return protocol;
    }

    public String getHost() {
        return host;
    }

    public HttpUrl(String url) throws MalformedURLException {
        URL url1 = new URL(url);
        host = url1.getHost();
        file = url1.getFile();
        file = isEmpty(file) ? "/" : file;
        protocol = url1.getProtocol();
        port = url1.getPort();
        port = port == -1 ? url1.getDefaultPort() : port;
    }


    private boolean isEmpty(String file) {
        if (file.length() == 0) {
            return true;
        }
        return false;
    }
}

import java.util.HashMap;
import java.util.Map;

public class Request {
    HttpUrl url;
    Map<String, String> headers = new HashMap<>();
    String method;

    public Request(Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers;
    }

    public String method() {
        return method;
    }

    public HttpUrl url() {
        return url;
    }

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

    public final static class Builder {

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

        public Builder() {
            this.method = "GET";
        }

        public Builder url(HttpUrl url) {
            this.url = url;
            return this;
        }

        public Builder addHeader(String name, String value) {
            headers.put(name, value);
            return this;
        }

        public Request build() {
            if (url == null) {
                throw new IllegalStateException("url is null");
            }
            return new Request(this);
        }
    }


}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值