手写tomcat(一)-知识储备

1.系统架构

1.1.加粗样式C/S 架构

1.1.1 概述

Client/Server 架构,即服务器/客户端架构。是大家熟知的软件系统体系结构,通过将任务合理分配到 Client 端和 Server 端,降低了系统的通讯开销,需要安装客户端才可进行管理操作。

常见的 C/S 架构的系统有: QQ、百度网盘等,以下为 C/S 架构的客户端登录页面
在这里插入图片描述
在这里插入图片描述

1.1.2 优点

(1) 界面和操作可以很丰富。
(2) 大部分数据保存在客户端,相对安全。
(3) 大部分功能都集成在客户端, 只需从服务器下载少量数据, 因此访问
速度较快。

1.1.3 缺点

(1) 升级维护工作量较大,每一个客户端都需要升级。
(2) 用户群固定。由于程序需要安装才可以使用,因此不适合面向一些不
可知的用户。

1.2 B/S 架构

1.2.1 概述

B/S 架构的全称为 Browser/Server,即浏览器/服务器结构。 Browser 指的是 Web 浏览器,极少数业务逻辑在前端实现,主要的业务逻辑在服务器端实现, Browser 客户端, WebApp 服务器端和 DB 端构成所谓的三层架构。 B/S 架构的系统无须特别安装,只有 Web 浏览器即可。 B/S 架构中,显示辑交给了 Web 浏览器,业务处理逻辑放在了 WebApp 上,这样就避免了庞大的胖客户端,减少了客户端的压力。因为客户端包含的逻辑很少,因此也被成为瘦客户端。

1.2.2 优点

(1) 客户端无需安装,有 Web 浏览器即可。
(2) BS 架构可以直接放在广域网上,通过一定的权限控制实现多客户访
问的目的,交互性较强。
(3) BS 架构无需升级多个客户端,升级服务器即可。

1.2.3 缺点

(1) 在跨浏览器上, BS 架构不尽如人意。
(2) 表现要达到 CS 架构的程度需要花费不少精力。
(3) 在速度和安全性上需要花费巨大的设计成本,这是 BS 架构的最大问题。

1.3 我们以后做什么

我们以后主要为企业内部提供解决方案,例如:企业内部的办公系统、供应链管理系统、客户关系管理系统等,而这些系统通常对界面的表现要求较低,对业务处理和数据处理要求较高,并且要求降低升级维护的成本, B/S 架构可以更好的被企业接受,所以我们以后主要的方向是开发基于 B/S 架构的应用, B/S 架构的开发通常又被叫做 Web 开发, Web 开发通常包括 Browser 浏览器端的开发以及Server 服务器端的开发。

1.4 WEB 开发相关职位

1.4.1 UI 设计师

(1) 下图取自智联招聘中的某条招聘信息:
在这里插入图片描述

1.4.2 WEB 前端开发工程师

(1)下图取自智联招聘中的某条招聘信息:
在这里插入图片描述

1.4.3 Java开发工程师

(1) 下图取自智联招聘中某条招聘信息:
在这里插入图片描述

2.B/S 架构原理剖析

2.1.接口与协议的作用

接口和协议可以理解为一种行业的标准或者规范,只有提前制定好规范和标准,将来各个部件或组件才可以做到无缝对接,接口的存在使整个系统变的具有很强的可接插特性,使整个系统各个组件之间达到松耦合,具备很强的高扩展力。

Java 语言连接数据库的 API 被称为 JDBC 接口,该接口是 SUN 公司负责制定的,连接数据库的 Java程序员只需要面向 JDBC 接口调用相关的方法即可完成底层数据库 CRUD 操作,该规范的出现让操作数据库的 Java 程序和底层具体的数据库产品解耦合, Java 程序无须依赖底层具体的数据库产品,可以真正做到“一套 Java 程序” 连接并操作各种不同类型的数据库系统。

再例如“不同版本的浏览器”都可以访问“百度网站”,并且最终在浏览器中显示的百度页面都是相同的,这说明“浏览器软件”和“百度服务器软件”之间是解耦合的,它们之所以可以做到解耦合就是因为这两个软件在互相传递数据的时候必然是遵守某种传送标准的,这种标准就是 W3C 制定的 HTTP 协议(超文本传输协议)。

2.2 B/S 架构原理图 1

在这里插入图片描述
B/S 架构的系统参与者:
第一: Web 客户端 Browser
第二: Web 服务器 Server
第三: WebApp
第四:数据库服务器

B/S 架构的系统中参与者之间的接口与协议:
第一: Web 客户端 Browser 和 Web 服务器端 Server 之间是 W3C 制定的 HTTP 协议。
第二: Web 服务器和 Web 应用之间是 SUN 制定的 Servlet 接口。
第三: Web 应用中的小 java 程序和数据库服务器之间是 SUN 制定的 JDBC 接口。

2.3 B/S 架构原理图 2

在这里插入图片描述

2.4 我们在该项目中做什么

2.4.1 主要目标

Web 服务器研发

2.4.2 角色: Web 服务器开发商

注:虽然 SUN 已经将 Servlet 接口制定好了,但是在该项目中为了让大家更好的理解 Servlet 接口,我们不使用 SUN 制定的 Servlet 接口,我们重新制定 Servlet 接口,所以我们开发的过程中角色可能会转为 SUN,严格意义上来说应该先制定 Servlet 接口,后进行 Web 服务器开发,但是这样大家可能很难理解为什么要制定这些接口,所以我们决定先开发 Web 服务器,在开发过程中,如果需要使用到某个接口,我们再进行定义。当我们的服务器研发成功之后,我们可以开发一个 web 应用对该服务器进行测试,在开发 web 应用的过程中我们的角色转为 javaweb 程序员。

2.5 我们为什么要做该项目

该项目中使用了大量的 JavaSE 相关内容,例如:多线程、网络编程、集合等,所以该项目可以巩固 Java 基础;我们以后主要从事的是基于 B/S 架构的 web 应用的开发,而我们开发的 web 应用主要部署在 web 服务器中,通过成功的开发 web 服务器可以帮助我们更好的更深入的理解后期要学习的内容,例如: Servlet、 JSP 等。所以该项目起到一个承上启下的作用。

3.HTTP 超文本传输协议

3.1 什么是协议

计算机 A 和计算机 B 之间在传送数据的时候,提前制定好的一种数据传送格式,计算机 A 向计算机 B 发送一个数据包,计算机 B 必须提前知道该数据包的数据格式,才可以成功的将该数据包中有价值的数据解析出来。

例如:小张和小王聊天,小张说:“你吃饭了吗?”,小王说:“吃了”。可见小张和小王可以正常沟通交流,他们为什么可以正常沟通交流呢?因为小张和小王都遵守同一套协议,该协议就是中国普通话协议,其实我们从幼儿园就开始学习这套协议了.

3.2 什么是 HTTP 协议

HTTP 协议是一种超文本传输协议,超文本表示不仅可以传送普通的文本,还可以传送一些二进制数据,例如:图片、声音、视频、流媒体等数据。
HTTP 协议是 W3C(万维网联盟组织)制定的,该协议规定了浏览器软件和 web 服务器软件之间在传送数据的时候采用什么样的格式。 这样就可以做到不同类型的浏览器访问不同类型的 Web 服务器。浏览器和 Web 服务器之间解耦合。

浏览器 Browser 向 Web 服务器发送数据,称为请求 request, Web 服务器向浏览器发送数据,称为响应 response。

3.3 HTTP 协议初步

3.3.1 HTTP 协议之请求协议

(1) 请求协议包括的主要部分

A、 请求行
B、 消息报头
C、 空白行
D、 请求体

(2) 请求协议详细内容
在这里插入图片描述

3.3.2 HTTP 协议之响应协议

(1) 响应协议包括的主要部分

A、 状态行
B、 响应报头
C、 空白行
D、 响应体

(2) 响应协议详细内容
在这里插入图片描述

4.Socket 编程

4.1 什么是 Socket 编程

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个 Socket。

Socket 的英文原义是“孔”或“插座”。通常也称作"套接字",用于描述 IP 地址和端口,可以用来实现不同计算机之间的通信。在 Internet 上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个 Socket,并绑定到一个端口上,不同的端口对应于不同的服务。 Socket 正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供 220 伏交流电, 有的提供 110 伏交流电,有的则提供有线电视节目。客户软件将插头插到不同编号的插座,就可以得到不同的服务。

4.2 连接过程

根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:
服务器监听,客户端请求,连接确认。

第一步:服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

第二步:客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

第三步:连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求

4.3 Java 中如何实现 Socket 编程

JavaSE 中提供了实现 Socket 编程的 API,让网络编程变的更简单,更加面向对象。实现两台计算机(两个服务)之间的通讯,至少编写以下的代码:

4.3.1 服务端 Server.java

(1) //创建服务端套接字,表示创建一个服务,并绑定端口号 8080

ServerSocket serverSocket = new ServerSocket(8080);

(2) //开始监听网络,准备接收客户端消息,程序在此等待,客户端发送
请求之后,接收客户端套接字

Socket clientSocket = serverSocket.accept();

(3) //接收客户端消息

BufferedReader br = new BufferedReader(new
InputStreamReader(clientSocket.getInputStream()));

(4) //读取客户端消息

String temp = null;
	While((temp = br.readLine()) != null){
	System.out.println(temp);
}

(5) 关闭流,关闭客户端套接字,关闭服务端套接字

package com.bruceliu.demo;

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

/**
 * @Auther: bruceliu
 * @Date: 2020/2/5 15:42
 * @QQ:1241488705
 * @Description:服务器端
 */
public class Server {

    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        BufferedReader br = null;

        try {
            //1.创建服务器端套接字对象,表示创建一个服务,并且将该服务绑定到8080端口上
            serverSocket = new ServerSocket(8080);
            System.out.println("服务器启动了,端口8080...");
            //2.开始监听网络,准备接收客户端的请求,程序在此等待,当客户端请求发起后,接收客户端套接字
            clientSocket = serverSocket.accept();
            System.out.println("clientSocket:" + clientSocket);
            //3.接收client消息
            br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            //4.读取client的消息
            String temp = null;
            while ((temp = br.readLine()) != null) {
                System.out.println(temp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭客户端套接字
            if (clientSocket != null) {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭服务器套接字
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
4.3.2 客户端 Client.java

(1) //1.创建客户端套接字,指向某台电脑的某台服务

Socket clientSocket = new Socket(192.168.0.160,8080);

(2) //2.发送消息

String msg = “Hello World!;
PrintWriter out = new PrintWriter(clientSocket.getOutputStream());

(3) //发送

out.print(msg);
out.flush();

(4) //关闭流,关闭客户端套接字

package com.bruceliu.demo;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * @Auther: bruceliu
 * @Date: 2020/2/5 15:57
 * @QQ:1241488705
 * @Description:客户端
 */
public class Client {

    public static void main(String[] args) {
        Socket clientSocket=null;
        PrintWriter out=null;
        try {
            //1.创建客户端套接字,指向某台计算机的某台服务器
            clientSocket=new Socket("127.0.0.1",8080);
            //2.发送消息
            String msg="hello,world!";
            out=new PrintWriter(clientSocket.getOutputStream());
            //3.发送
            out.print(msg);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(out!=null){
                out.close();
            }
            //关闭客户端套接字
            if(clientSocket!=null){
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4.4 读取从浏览器发送的 HTTP 请求协议

4.4.1 上面的客户端程序不再使用 java 代码,我们尝试将“客户端程序”改为“浏览器客户端软件”,编写以下服务器端程序:
package com.bruceliu.demo;

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

/**
 * @Auther: bruceliu
 * @Date: 2020/2/5 15:42
 * @QQ:1241488705
 * @Description:服务器端
 */
public class Server {

    public static void main(String[] args) {

        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        BufferedReader br = null;

        try {
            //1.创建服务器端套接字对象,表示创建一个服务,并且将该服务绑定到8080端口上
            serverSocket = new ServerSocket(8080);
            System.out.println("服务器启动了,端口8080...");
            //2.开始监听网络,准备接收客户端的请求,程序在此等待,当客户端请求发起后,接收客户端套接字
            clientSocket = serverSocket.accept();
            System.out.println("clientSocket:" + clientSocket);
            //3.接收client消息
            br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            //4.读取client的消息
            String temp = null;
            while ((temp = br.readLine()) != null) {
                System.out.println(temp);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭客户端套接字
            if (clientSocket != null) {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //关闭服务器套接字
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
4.4.2 打开 FF 浏览器(标准浏览器),在地址栏上输入以下 URL,然后敲回车键:

在这里插入图片描述

4.4.3 Java 控制台读取到请求协议的全部内容,如下图:

在这里插入图片描述

发布了274 篇原创文章 · 获赞 80 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/104180334