├── .gitignore ├── README.md ├── build.gradle ├── settings.gradle └── src └── main └── java └── com └── yanzhenjie └── http ├── client └── HttpClient.java └── server ├── HttpServer.java └── RequestHandler.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | # Compiled class file 4 | *.class 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.nar 19 | *.ear 20 | *.zip 21 | *.tar.gz 22 | *.rar 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | 27 | .gradle 28 | .idea 29 | build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HttpImpl 2 | 3 | 该项目是使用 Socket 实现的 HttpServer 和 HttpClient,主要是配合博客[HTTP 的协议理解与服务端和客户端的设计实现](https://yanzhenjie.blog.csdn.net/article/details/93098495)。 4 | 5 | 文章地址:[https://yanzhenjie.blog.csdn.net/article/details/93098495](https://yanzhenjie.blog.csdn.net/article/details/93098495) 6 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'com.yanzhenjie.http.client' 6 | version '1.0-SNAPSHOT' 7 | 8 | sourceCompatibility = 1.8 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | implementation fileTree(dir: 'libs', include: ['*.jar']) 16 | implementation 'org.apache.commons:commons-lang3:3.9' 17 | implementation 'commons-io:commons-io:2.6' 18 | implementation 'org.apache.commons:commons-collections4:4.3' 19 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'HttpImpl' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/yanzhenjie/http/client/HttpClient.java: -------------------------------------------------------------------------------- 1 | package com.yanzhenjie.http.client; 2 | 3 | import java.io.*; 4 | import java.net.InetSocketAddress; 5 | import java.net.Socket; 6 | import java.nio.charset.Charset; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class HttpClient { 11 | 12 | private static final Charset UTF8 = Charset.forName("utf-8"); 13 | 14 | private void start() throws Exception { 15 | System.out.println("------------------ 开始请求 ------------------"); 16 | 17 | Socket socket = new Socket(); 18 | socket.setSoTimeout(10 * 1000); 19 | socket.connect(new InetSocketAddress("www.csdn.net", 80), 10 * 1000); 20 | // socket.connect(new InetSocketAddress("192.168.0.111", 8888), 10 * 1000); 21 | 22 | System.out.println("---->>>> 发送请求 <<<<----"); 23 | String data = "恰同学少年"; 24 | sendRequest(socket, data.getBytes(UTF8)); 25 | 26 | System.out.println("---->>>> 读取响应 <<<<----"); 27 | firstRead(socket); 28 | // secondRead(socket); 29 | // thirdRead(socket); 30 | 31 | socket.close(); 32 | System.out.println("------------------请求完成------------------"); 33 | } 34 | 35 | /** 36 | * 发送请求。 37 | */ 38 | private void sendRequest(Socket socket, byte[] data) throws IOException { 39 | OutputStream os = socket.getOutputStream(); 40 | 41 | // 发送请求头 42 | PrintStream print = new PrintStream(os); 43 | print.println("POST /abc/dev?ab=cdf HTTP/1.1"); 44 | print.println("Host: www.csdn.net"); 45 | print.println("User-Agent: HttpClient/1.0"); 46 | print.println("Content-Length: " + data.length); 47 | print.println("Content-Type: text/plain; charset=utf-8"); 48 | print.println("Accept: *"); 49 | print.println(); 50 | 51 | // 发送请求数据 52 | print.write(data); 53 | os.flush(); 54 | } 55 | 56 | /** 57 | * 读取响应:一次全部输出。 58 | */ 59 | private void firstRead(Socket socket) throws IOException { 60 | InputStream is = socket.getInputStream(); 61 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 62 | byte[] buffer = new byte[2048]; 63 | int len; 64 | while ((len = is.read(buffer)) > 0) { 65 | bos.write(buffer, 0, len); 66 | if (len < 2048) break; 67 | } 68 | System.out.println(new String(bos.toByteArray())); 69 | } 70 | 71 | /** 72 | * 读取响应:按照HTTP响应数据结构分割读取。 73 | */ 74 | private void secondRead(Socket socket) throws IOException { 75 | BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 76 | 77 | System.out.println("-->>>> 状态行 <<<<--"); 78 | String statusLine = reader.readLine(); 79 | System.out.println(statusLine); 80 | 81 | System.out.println("-->>>> 响应头 <<<<--"); 82 | String header = reader.readLine(); 83 | while (!"".equals(header)) { 84 | System.out.println(header); 85 | header = reader.readLine(); 86 | } 87 | 88 | System.out.println("-->>>> 数据 <<<<---"); 89 | CharArrayWriter charArray = new CharArrayWriter(); 90 | char[] buffer = new char[2048]; 91 | int len; 92 | while ((len = reader.read(buffer)) > 0) { 93 | charArray.write(buffer, 0, len); 94 | if (len < 2048) break; 95 | } 96 | System.out.println(new String(charArray.toCharArray())); 97 | } 98 | 99 | /** 100 | * 读取响应内容:按照HTTP响应数据结构分割读取,并适当封装。 101 | */ 102 | private void thirdRead(Socket socket) throws IOException { 103 | BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 104 | 105 | System.out.println("-->>>> 状态行 <<<<--"); 106 | String statusLine = reader.readLine(); 107 | System.out.println(statusLine); 108 | 109 | System.out.println("-->>>> 响应头 <<<<--"); 110 | long contentLength = 0; 111 | Map headers = new HashMap<>(); 112 | 113 | String header = reader.readLine(); 114 | while (!"".equals(header)) { 115 | String[] array = header.split(":"); 116 | String key = array[0].trim(); 117 | String value = array[1].trim(); 118 | headers.put(key, value); 119 | 120 | if (key.equalsIgnoreCase("Content-Length")) { 121 | contentLength = Long.parseLong(value); 122 | } 123 | header = reader.readLine(); 124 | } 125 | 126 | for (String key : headers.keySet()) { 127 | System.out.println(key + ": " + headers.get(key)); 128 | } 129 | 130 | System.out.println("-->>>> 数据 <<<<--"); 131 | CharArrayWriter charArray = new CharArrayWriter(); 132 | char[] buffer = new char[2048]; 133 | int totalLen = 0, len; 134 | while ((len = reader.read(buffer)) > 0) { 135 | charArray.write(buffer, 0, len); 136 | totalLen += len; 137 | if (totalLen == contentLength) break; 138 | } 139 | System.out.println(new String(charArray.toCharArray())); 140 | } 141 | 142 | public static void main(String[] args) { 143 | try { 144 | HttpClient http = new HttpClient(); 145 | http.start(); 146 | } catch (Exception e) { 147 | e.printStackTrace(); 148 | } 149 | 150 | System.exit(0); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/com/yanzhenjie/http/server/HttpServer.java: -------------------------------------------------------------------------------- 1 | package com.yanzhenjie.http.server; 2 | 3 | import java.net.InetSocketAddress; 4 | import java.net.ServerSocket; 5 | import java.net.Socket; 6 | 7 | public class HttpServer { 8 | 9 | private void start() throws Exception { 10 | ServerSocket server = new ServerSocket(); 11 | server.bind(new InetSocketAddress("192.168.0.111", 8888)); 12 | System.out.println("---->>>> 服务器已经启动 <<<<----"); 13 | 14 | while (true) { 15 | Socket socket = server.accept(); 16 | 17 | InetSocketAddress address = (InetSocketAddress) socket.getRemoteSocketAddress(); 18 | System.out.println("---->>>> 收到请求 <<<<----"); 19 | System.out.println(address.getHostName()); 20 | 21 | RequestHandler handler = new RequestHandler(socket); 22 | handler.start(); 23 | } 24 | } 25 | 26 | public static void main(String[] args) { 27 | try { 28 | HttpServer http = new HttpServer(); 29 | http.start(); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | 34 | System.exit(0); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/yanzhenjie/http/server/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.yanzhenjie.http.server; 2 | 3 | import java.io.*; 4 | import java.net.Socket; 5 | import java.nio.charset.Charset; 6 | 7 | public class RequestHandler extends Thread { 8 | 9 | private static final Charset UTF8 = Charset.forName("utf-8"); 10 | 11 | private Socket mSocket; 12 | 13 | public RequestHandler(Socket mSocket) { 14 | this.mSocket = mSocket; 15 | } 16 | 17 | @Override 18 | public void run() { 19 | System.out.println("---->>>> 读取请求 <<<<----"); 20 | try { 21 | readRequest(mSocket); 22 | } catch (IOException e) { 23 | throw new RuntimeException("Network is wrong."); 24 | } 25 | 26 | System.out.println("---->>>> 发送响应 <<<<----"); 27 | try { 28 | String data = "天上掉下个林妹妹"; // 相当于服务端API处理业务造数据 29 | sendResponse(mSocket, data.getBytes(UTF8)); 30 | } catch (IOException e) { 31 | throw new RuntimeException("This is a bug."); 32 | } 33 | 34 | try { 35 | mSocket.close(); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | 40 | System.out.println("---->>>> 响应结束 <<<<----"); 41 | } 42 | 43 | /** 44 | * 读取请求。 45 | */ 46 | private void readRequest(Socket socket) throws IOException { 47 | InputStream is = socket.getInputStream(); 48 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 49 | byte[] buffer = new byte[2048]; 50 | int len; 51 | while ((len = is.read(buffer)) > 0) { 52 | bos.write(buffer, 0, len); 53 | if (len < 2048) break; 54 | } 55 | System.out.println(new String(bos.toByteArray())); 56 | } 57 | 58 | /** 59 | * 发送响应。 60 | */ 61 | private void sendResponse(Socket socket, byte[] data) throws IOException { 62 | OutputStream os = socket.getOutputStream(); 63 | 64 | // 发送响应头 65 | PrintStream print = new PrintStream(os); 66 | print.println("HTTP/1.1 200 Beautiful"); 67 | print.println("Server: HttpServer/1.0"); 68 | print.println("Content-Length: " + data.length); 69 | print.println("Content-Type: text/plain; charset=utf-8"); 70 | print.println(); 71 | 72 | // 发送响应数据 73 | print.write(data); 74 | os.flush(); 75 | } 76 | } 77 | --------------------------------------------------------------------------------