基于TCP手动封装http协议

 1. 客户端,浏览器
 2. 服务端基于 socket的 协议解析
 

1. 服务端接收GET请求

运行服务端代码 HttpServerGet,浏览器客户端 请求路径:http://localhost:8888/  GET请求直接放入浏览器地址栏即可

package com.denganzhi.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class HttpServerGet {
	
	public static void main(String[] args) {
		 //1.. 创建服务器,  指定端口
		ServerSocket server;
		try {
			server = new ServerSocket(8888);
			 // 2. 指定客户端   阻塞式
			//  完成 三次握手 , 建立管道
			System.out.println("服务器阻塞,等待客户端连接");
			Socket socket= server.accept();
			System.out.println("一个客户端建立连接");
			String msg=null;
	BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
	StringBuffer sb=new StringBuffer();
	while((msg=br.readLine()).length() > 0) {
		sb.append(msg);
		sb.append("\n");
		if(msg==null) {
			break;
		}
	}
	String reqStr= sb.toString();
	System.out.println("reqStr:"+reqStr);
	// 请求路径:http://localhost:8888/  GET请求直接放入浏览器地址栏即可
 
	// 输出内容
//reqStr:GET / HTTP/1.1     //GET请求行 
//Host: localhost:8888      // GET请求头,GET没有请求体
//Connection: keep-alive
//Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8  
//Upgrade-Insecure-Requests: 1
//User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
//Accept-Encoding: gzip, deflate, sdch
//Accept-Language: zh-CN,zh;q=0.8


		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}   
	
		
	}

}


 2.服务端接收POST请求

客户端代码index.html:     发送http://localhost:8888/  POST 请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		
		<form method="post" action="http://localhost:8888/">
			用户名:<input type="text" name="username" />
			密码:<input type="text" name="pwd" />
			<input type="submit" value="登录" />
			
		</form>
		
	</body>
</html>

服务端解析POST请求HttpServerPost,拼接响应POST请求

 获取post请求内容:
post请求结果是:POST / HTTP/1.1
Host: localhost:7676
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
Connection: keep-alive
Upgrade-Insecure-Requests: 1

username=eee&pwd=
post请求响应内容:
响应行:HTTP/1.1 404 NOTFOUNDPAGER
响应头
Server:xiaozhi Server/0.0.1
Date:Mon Apr 06 21:37:10 CST 2020
Content-type:text/html;charset=GBK
Content-Length:0
 响应体:  HTML代码

package com.denganzhi.socket;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class HttpServerPost {
	// 请求路径:http://localhost:9999/
	public static void main(String[] args) {
		
		 //1.. 创建服务器,  指定端口
			ServerSocket server;
		
				try {
					server = new ServerSocket(9999);
					 // 2. 指定客户端   阻塞式
					//  完成 三次握手 , 建立管道
					System.out.println("服务器阻塞,等待客户端连接");
					Socket client= server.accept();
					System.out.println("一个客户端建立连接");
					byte[] data=new byte[20480];
					// 接收客户端请求POST
			int len=client.getInputStream().read(data);
  String requestInfo=new String(data,0,len);
  
  
//  post请求结果是:POST / HTTP/1.1      请求行 
//  Host: localhost:9999             请求头
//  Connection: keep-alive
//  Content-Length: 20
//  Cache-Control: max-age=0
//  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
//  Origin: http://127.0.0.1:8020
//  Upgrade-Insecure-Requests: 1
//  User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
//  Content-Type: application/x-www-form-urlencoded
//  Referer: http://127.0.0.1:8020/HelloHBuilder/index2.html?__hbt=1586174211226
//  Accept-Encoding: gzip, deflate
//  Accept-Language: zh-CN,zh;q=0.8
//
//  username=111&pwd=111             请求体,请求体和请求头中间有换行
  
  
  System.out.println("post请求结果是:"+requestInfo);
  /***
   * 
   * 响应行:HTTP/1.1 200 OK
   * 响应头:
   * Server:xiaozhi Server/0.0.1
Date:Mon Apr 06 20:34:05 CST 2020
Content-type:text/html;charset=GBK
Content-Length:144
    响应头: 可以是text/html : 网页内容
    可以是json
  可会是文件 流
  可以是图片  
   * 
   */
String CRLF="\r\n";	
String BLANK=" ";	
  // 响应
  StringBuilder responseContext=new StringBuilder();
  responseContext.append("<!DOCTYPE html>\r\n" + 
  		"<html>\r\n" + 
  		"	<head>\r\n" + 
  		"		<meta charset=\"UTF-8\">\r\n" + 
  		"		<title>小置同学</title>\r\n" + 
  		"	</head>\r\n" + 
  		"	<body>\r\n" + 
  		"		 hello!小置同学\r\n" + 
  		"	</body>\r\n" + 
  		"</html>\r\n" + 
  		"");
  System.out.println("响应体:"+responseContext);
 
  StringBuilder response =new StringBuilder();
  //1)  HTTP协议版本、状态代码、描述
  response.append("HTTP/1.1").append(BLANK).append("200").
  append(BLANK).append("OK").append(CRLF);
  System.out.println("响应行:"+response.toString());
  //2)  响应头(Response Head)
  response.append("Server:xiaozhi Server/0.0.1").append(CRLF);
  response.append("Date:").append(new Date()).append(CRLF);
  response.append("Content-type:text/html;charset=GBK").
  append(CRLF);
  //正文长度 :字节长度
  response.append("Content-Length:").
  // 正文长度,这里必须是字节数正文的
  append(responseContext.toString().getBytes().length).
  append(CRLF);
  //3)正文之前
  response.append(CRLF);
  //4)正文
  response.append(responseContext);
  
 
  System.out.println("响应头:"+response);
  
  //输出流
  BufferedWriter bw = new BufferedWriter(new 
  OutputStreamWriter(client.getOutputStream()));
  bw.write(response.toString());
  bw.flush();
  bw.close();
  

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
				
				
	}

}

3.获取状态码、请求参数解析, 实现tomcat功能  HttpServerPostAddStatus

package com.denganzhi.socket;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class HttpServerPostAddStatus {
	// 请求路径:http://localhost:7676/
	public static void main(String[] args) {
		
		 //1.. 创建服务器,  指定端口
			ServerSocket server;
		
				try {
					server = new ServerSocket(7676);
					 // 2. 指定客户端   阻塞式
					//  完成 三次握手 , 建立管道
					System.out.println("HttpServerPostAddStatus->服务器阻塞,等待客户端连接");
					Socket client= server.accept();
					System.out.println("一个客户端建立连接");
					byte[] data=new byte[20480];
					// 接收客户端请求POST
			int len=client.getInputStream().read(data);
  String requestInfo=new String(data,0,len);
  
  
//  post请求结果是:POST / HTTP/1.1      请求行 
//  Host: localhost:9999             请求头
//  Connection: keep-alive
//  Content-Length: 20
//  Cache-Control: max-age=0
//  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
//  Origin: http://127.0.0.1:8020
//  Upgrade-Insecure-Requests: 1
//  User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
//  Content-Type: application/x-www-form-urlencoded
//  Referer: http://127.0.0.1:8020/HelloHBuilder/index2.html?__hbt=1586174211226
//  Accept-Encoding: gzip, deflate
//  Accept-Language: zh-CN,zh;q=0.8
//
//  username=111&pwd=111             请求体,请求体和请求头中间有换行
  
  
  System.out.println("post请求结果是:"+requestInfo);
  /***
   * 
   * 响应行:HTTP/1.1 200 OK
   * 响应头:
   * Server:xiaozhi Server/0.0.1
Date:Mon Apr 06 20:34:05 CST 2020
Content-type:text/html;charset=GBK
Content-Length:144
    响应头: 可以是text/html : 网页内容
    可以是json
  可会是文件 流
  可以是图片  
   * 
   */
String CRLF="\r\n";	
String BLANK=" ";	
  // 响应
  StringBuilder responseContext=new StringBuilder();
//  responseContext.append("<!DOCTYPE html>\r\n" + 
//  		"<html>\r\n" + 
//  		"	<head>\r\n" + 
//  		"		<meta charset=\"UTF-8\">\r\n" + 
//  		"		<title>小置同学</title>\r\n" + 
//  		"	</head>\r\n" + 
//  		"	<body>\r\n" + 
//  		"		 hello!小置同学\r\n" + 
//  		"	</body>\r\n" + 
//  		"</html>\r\n" + 
//  		"");
  System.out.println("响应体:"+responseContext);
  
  StringBuilder response =new StringBuilder();
  //1)  HTTP协议版本、状态代码、描述
  // 状态码描述
  int statusCode=404;
  response.append("HTTP/1.1").append(BLANK).append(statusCode);
  switch (statusCode) {
case 200:
	 response.append(BLANK).append("OK").append(CRLF);
	break;
case 404:
	 response.append(BLANK).append("NOTFOUNDPAGER").append(CRLF);
	break;
case 500:
	 response.append(BLANK).append("ServerError").append(CRLF);
	break;
}
 
 
  System.out.println("响应行:"+response.toString());
  //2)  响应头(Response Head)
  response.append("Server:xiaozhi Server/0.0.1").append(CRLF);
  response.append("Date:").append(new Date()).append(CRLF);
  response.append("Content-type:text/html;charset=GBK").
  append(CRLF);
  //正文长度 :字节长度
  response.append("Content-Length:").
  // 正文长度,这里必须是字节数正文的
  append(responseContext.toString().getBytes().length).
  append(CRLF);
  //3)正文之前
  response.append(CRLF);
  //4)正文
  response.append(responseContext);
  
 
  System.out.println("响应头:"+response);
  
  //输出流
  BufferedWriter bw = new BufferedWriter(new 
  OutputStreamWriter(client.getOutputStream()));
  bw.write(response.toString());
  bw.flush();
  bw.close();
  

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
				
				
	}

}

火狐浏览器 抓包查看 请求、响应状态码:

发布了121 篇原创文章 · 获赞 139 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/105352678