实现一个简易的Tomcat

实现一个简易的Tomcat

一、HTTP协议

1协议的概念

一方或者多方约定好的一个规范。

TCP(传输控制协议)协议

UDP(数据报协议)协议

IP(Internet Protocol 网络协议)协议

1.1 HTTP协议的介绍

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。

它是基于TCP(面向连接的可靠地传输协议(三次握手 四次挥手))协议传输数据。

在这里插入图片描述

在这里插入图片描述

1.2 HTTP协议的优势
  1. 支持客户/服务器模式。 (B/S 和 C/S架构)
  2. **简单快速:**客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。
    由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  3. **灵活:**HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  4. **无连接:**无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  5. **无状态:**HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

导致它成为了我们万维网世界的基础传输协议。当然除了HTTP协议之外还有其他的:FTP协议、SSH协议、SMTP协议…

1.3HTTP协议的(报文)规范

请求规范:

请求行: 用来标注请求资源地址的
	请求方式 资源地址URL 协议版本 回车符\r和换行符\n
请求头: 用来标注请求携带的一些特殊要求以及客户端一些标识
	键值对存储的信息
请求体: 用来传输参数数据的,GET请求没有请求体

例如:
GET http://www.baidu.com HTTP/1.1必须换行
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;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, br必须换行
必须有一个空行
[username=xx&password=xxx]

响应规范:

响应行:
	协议版本 响应编码(状态码) 响应提示
响应头:
	键值对
响应体:
	响应的数据,什么格式都可以
例如:
HTTP/1.1 200 ok必须有换行
Date: Thu, 27 Jun 2019 01:06:45 GMT必须有换行
Server: Apache必须有换行
Content-Type: text/html;charset=UTF-8必须有换行
必须要有空行
响应数据

HTTP协议的状态码分类:

  • 1xx:服务器已经接收到请求,需要等待下一步处理
  • 2xx:客户端请求成功,服务器接收且处理成功
  • 3xx:重定向 客户端的请求需要进一步请求才能处理完毕
  • 4xx:客户端请求错误
  • 5xx:服务端处理错误

HTTP协议的常见状态码:

  • 200:请求成功 并且处理完毕 (ok)
  • 304:请求被重定向到缓存。(Not Modified)
  • 302:请求被重定向到另一个资源 (found)
  • 404:请求错误,资源不存在 (not found)
  • 400:请求错误,服务端对请求资源不理解 (bad request)
  • 401:请求错误,未授权的客户端(unauthorized)
  • 403:请求错误,服务端拒绝处理请求(forbidden)
  • 500:服务器处理错误 一般都是服务器代码出bug了(server internal error)

二、 实现一个简易的静态服务器(服务器软件)

静态服务器是访问静态资源。

/**
 * 静态服务器
 * @author 周太阳
 */
public class Server2 {
	
	public static void main(String[] args) {
	    try {
            ServerSocket serverSocket = new ServerSocket(2222);
            System.out.println("服务器启动!");
            while (true) {
                Socket socket = serverSocket.accept();
                new Thread(new Runnable(){
                    @Override
                    public void run() {
                        start(socket);
                    }
                }).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
	}
	private static void start(Socket socket) {
		OutputStream os = null;
		BufferedOutputStream bos = null;
		InputStream is = null;
		BufferedReader br = null;
		try {
			// 获得输入流
			is = socket.getInputStream();
			// 创建字符输入流
			br = new BufferedReader(new InputStreamReader(is));
			// 获得输出流
			os = socket.getOutputStream();
			// 创建高效字节流
			bos = new BufferedOutputStream(os);
			// 响应行
			bos.write("HTTP/1.1 200 OK\n".getBytes());
			// 响应头
			bos.write("Content-Type: image/png \n".getBytes());
			bos.write("\r\n".getBytes());
			// 读取服务器文件
			FileInputStream fis = new FileInputStream("E:\\Download\\day49-实现一个简单的Tomcat\\01_code\\day49-simple-tomcat\\WebContent\\img\\3.png");
			byte[] buffer = new byte[2048];
			int len = -1;
			while((len = fis.read(buffer)) != -1) {
				// 给浏览器发送文件
				bos.write(buffer, 0, len);
			}
			bos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if (bos != null) {
					bos.close();
				}
				if (os != null) {
					os.close();
				}
				if (br != null) {
					br.close();
				}
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

三、实现一个简易的动态服务器(服务器软件)

动态服务器是可以根据地址去执行对应的请求处理(执行Java代码处理)

/**
 * Web服务器
 * @author 周太阳
 * 2019年6月28日 上午9:05:41
 */
public class Server {
    /**
     * 获得当前项目的绝对路径
     */
	private static final String FIRST_PATH = System.getProperty("user.dir");
	/**
	 * 当前项目的web内容文件夹
	 */
	private static final String PROJECT_PATH = "/Simple-Web";
	
	public static void main(String[] args) {
		try {
			ServerSocket serverSocket = new ServerSocket(2222);
			System.out.println("服务器启动!");
			while (true) {
				Socket socket = serverSocket.accept();
				new Thread(new Runnable(){
					@Override
					public void run() {
						start(socket);
					}
				}).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
    
	private static void start(Socket socket) {
		OutputStream os = null;
		BufferedOutputStream bos = null;
		InputStream is = null;
		BufferedReader br = null;
		try {
			// 获得输入流
			is = socket.getInputStream();
			// 创建字符输入流
			br = new BufferedReader(new InputStreamReader(is));
			// 获得输出流
			os = socket.getOutputStream();
			// 创建高效字节流
			bos = new BufferedOutputStream(os);
			// 获取用户访问信息
			String request = br.readLine();
			// 获取用户访问相对地址
			String requestURL = getRequestPath(request);
			// 响应行
			bos.write("HTTP/1.1 200 OK\n".getBytes());
			// 响应头
			if (requestURL.endsWith(".html")) {
				bos.write("Content-Type: text/html; charset=utf-8\n".getBytes());
			}else {
				bos.write("Content-Type: image/png \n".getBytes());
			}
			bos.write("\r\n".getBytes());
			// 读取服务器文件
			FileInputStream fis = new FileInputStream(FIRST_PATH+PROJECT_PATH+requestURL);
			byte[] buffer = new byte[2048];
			int len = -1;
			while((len = fis.read(buffer)) != -1) {
				// 给浏览器发送文件
				bos.write(buffer, 0, len);
			}
			bos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if (bos != null) {
					bos.close();
				}
				if (os != null) {
					os.close();
				}
				if (br != null) {
					br.close();
				}
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * GET /index.html HTTP/1.1
	 * 利用split方法取到/index.html
	 * @param request 返回/index.html
	 * @return
	 */
	private static String getRequestPath(String request) {
		String[] split =request.split(" ");
		return split[1];
	}
}

注意:如果使用高效字符输出流会无法输出文件,需要用字节流输出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值