目录
前言
本文将介绍 Java Web 服务器是如何运行的, Web 服务器也称为超文本传输协议( HyperText Transfer Protocol, HTTP)服务器, 因为它使用 Http 与其客户端(通常是 Web 浏览器)进行通信, 基于 Java 的 Web 服务器会使用两个重要的类: java.net.Socket 类和java.net.ServerSocket 类, 并通过发送 Http 消息进行通信. 我们先花一些篇幅介绍 Http 协议(如果同学们熟悉HTTP协议可直接跳过)和这两个类, 然后写一个简单的 Web 服务器.
一、什么是Http协议?
HTTP协议 超文本传输协议 由万维网制定(w3c)
是浏览器与服务器通讯的应用层协议,规定了浏览器与服务器之间的交互规则以及交互数据的
格式信息等。
二、服务端与客户端的交互规则
1.定义
- 要求浏览器与服务端之间必须遵循一问一答的规则,即:浏览器与服务端建立TCP连接后需要
先发送一个请求(问)然后服务端接收到请求并予以处理后再发送响应(答)。注意,服务端永远
不会主动给浏览器发送信息。 - HTTP要求浏览器与服务端的传输层协议必须是可靠的传输,因此是使用TCP协议作为传输层
协议的。 - HTTP协议对于浏览器与服务端之间交互的数据格式,内容也有一定的要求。
浏览器给服务端发送的内容称为请求Request
服务端给浏览器发送的内容称为响应Response - 请求和响应中大部分内容都是文本信息(字符串),并且这些文本数据使用的字符集为:
ISO8859-1.这是一个欧洲的字符集,里面是不支持中文的!!!。而实际上请求和响应出现
的字符也就是英文,数字,符号。
2.请求Request
- 请求是浏览器发送给服务端的内容,HTTP协议中一个请求由三部分构成:
分别是:请求行,消息头,消息正文。消息正文部分可以没有。 - 1:请求行
请求行是一行字符串,以连续的两个字符(回车符和换行符)作为结束这一行的标志。
回车符:在ASC编码中2进制内容对应的整数是13.回车符通常用cr表示。
换行符:在ASC编码中2进制内容对应的整数是10.换行符通常用lf表示。
回车符和换行符实际上都是不可见字符。 - 请求行分为三部分:
请求方式(SP)抽象路径(SP)协议版本(CRLF) 注:SP是空格
GET /index.html HTTP/1.1 - 2:消息头
消息头是浏览器可以给服务端发送的一些附加信息,有的用来说明浏览器自身内容,有的
用来告知服务端交互细节,有的告知服务端消息正文详情等。 - 消息头由若干行组成,每行结束也是以CRLF标志。
每个消息头的格式为:消息头的名字(:SP)消息的值(CRLF)
消息头部分结束是以单独的(CRLF)标志。
例如:Host: localhost:8088(CRLF) Connection: keep-alive(CRLF) Upgrade-Insecure-Requests: 1(CRLF) User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36(CRLF) Sec-Fetch-User: ?1(CRLF) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9(CRLF) Sec-Fetch-Site: none(CRLF) Sec-Fetch-Mode: navigate(CRLF) Accept-Encoding: gzip, deflate, br(CRLF) Accept-Language: zh-CN,zh;q=0.9(CRLF)(CRLF)
- 3:消息正文
消息正文是2进制数据,通常是用户上传的信息,比如:在页面输入的注册信息,上传的
附件等内容。
例如:crlf GET /index.html HTTP/1.1 Host: localhost:8088 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36 Sec-Fetch-User: ?1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: none Sec-Fetch-Mode: navigate Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 1010101010110110110101....
3.响应Response
- 响应是服务端发送给客户端的内容。一个响应包含三部分:状态行,响应头,响应正文
-
1:状态行
状态行是一行字符串(CRLF结尾),并且状态行由三部分组成,格式为:
protocol(SP)statusCode(SP)statusReason(CRLF)
协议版本(SP)状态代码(SP)状态描述(CRLF)
例如:
HTTP/1.1 200 OK状态代码是一个3位数字,分为5类:
1xx:保留
2xx:成功,表示处理成功,并正常响应
3xx:重定向,表示处理成功,但是需要浏览器进一步请求
4xx:客户端错误,表示客户端请求错误导致服务端无法处理
5xx:服务端错误,表示服务端处理请求过程出现了错误 -
具体的数字在HTTP协议手册中有相关的定义,可参阅。
状态描述手册中根据不同的状态代码有参考值,也可以自行定义。通常使用参考值即可。 -
响应头:
响应头与请求中的消息头格式一致,表示的是服务端发送给客户端的附加信息。 -
响应正文:
2进制数据部分,包含的通常是客户端实际请求的资源内容。响应的大致内容:
HTTP/1.1 200 OK(CRLF)
Content-Type: text/html(CRLF)
Content-Length: 2546(CRLF)(CRLF)
1011101010101010101...... -
这里的两个响应头:
Content-Type是用来告知浏览器响应正文中的内容是什么类型的数据(图片,页面等等)
不同的类型对应的值是不同的,比如:
文件类型 Content-Type对应的值
html text/html
css text/css
js application/javascript
png image/png
gif image/gif
jpg image/jpeg -
Content-Length是用来告知浏览器响应正文的长度,单位是字节。
-
浏览器接收正文前会根据上述两个响应头来得知长度和类型从而读取出来做对应的处理以
显示给用户看。
4.Socket 类
- 套接字是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。放在两 个不同计算机上的两个应用可以通过连接发送和接受字节流。为了从你的应用发送一条信息到另 一个应用,你需要知道另一个应用的 IP 地址和套接字端口。在 Java 里边,套接字指的是
java.net.Socket
类。 - 要创建一个套接字,你可以使用 Socket 类众多构造方法中的一个。其中一个接收主机名称 和端口号:
public Socket (java.lang.String host, int port)
在这里主机是指远程机器名称或者 IP 地址,端口是指远程应用的端口号。例如,要连接 yahoo.com 的 80 端口,你需要构造以下的 Socket 对象:
new Socket ("localhost", 8088);
一旦你成功创建了一个 Socket 类的实例,你可以使用它来发送和接受字节流。要发送字节 流,你首先必须调用Socket类的getOutputStream方法来获取一个java.io.OutputStream对象。 要 发 送 文 本 到 一 个 远 程 应 用 , 你 经 常 要 从 返 回 的 OutputStream 对 象 中 构 造 一 个 java.io.PrintWriter 对象。要从连接的另一端接受字节流,你可以调用 Socket 类的 getInputStream 方法用来返回一个 java.io.InputStream 对象。
5.ServerSocket 类
- Socket 类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构 造的套接字,现在,假如你想实施一个服务器应用,例如一个 HTTP 服务器或者 FTP 服务器,你 需要一种不同的做法。这是因为你的服务器必须随时待命,因为它不知道一个客户端应用什么时 候会尝试去连接它。为了让你的应用能随时待命,你需要使用 java.net.ServerSocket 类。这是 服务器套接字的实现。
- ServerSocket 和 Socket 不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服 务器套接字获得一个连接请求,它创建一个 Socket 实例来与客户端进行通信。
-
要创建一个服务器套接字,你需要使用 ServerSocket 类提供的四个构造方法中的一个。你 需要指定 IP 地址和服务器套接字将要进行监听的端口号。通常,IP 地址将会是 127.0.0.1,也 就是说,服务器套接字将会监听本地机器。服务器套接字正在监听的 IP 地址被称为是绑定地址。 服务器套接字的另一个重要的属性是 backlog,这是服务器套接字开始拒绝传入的请求之前,传 入的连接请求的最大队列长度。
其中一个 ServerSocket 类的构造方法如下所示:
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
下一篇文章开始将借助开发工具来阐述Tomcat的底层实现原理