TCP/IP 协议与 HTTP协议

不得不提的TCP/IP协议,TCP/IP不是两个协议,而是一整个协议栈;

TCP/IP包含如下图四层:其中每一层都使用着一个或者多个协议,遵循这些协议就可以实现不同设备之间的轻松通信

  • 应用层(Http协议 DNS协议 Email协议…)
  • 传输层(TCP协议 UDP协议)
  • 网络层 (IP协议 )
  • 网络接口层(设备的驱动程序+接口卡)

其中TCP(transfer control protocol)协议是传输层的协议,他是面向连接的,基于字节流的传输通信协议, Java对Tcp的支持体现在它的网络编程包中的SocketServerSocket的封装.

特点:

  1. 面向连接的(三次捂手建立连接,四次挥手释放连接)
  2. 点对点的通信
  3. 高可靠(得益于第一个特点)
  4. 占用的系统资源多,效率低

在java的网络通信中,Tcp基于字节流进行数据包的传输, 客户端的Socket和服务端的ServerSocket内置了输入输出流,都过彼此的IO流进行通信

TCP的三次握手和四次挥手

三次握手

假设A B两个客户端进行数据的传输,在真正进行数据的传输之前,两者会用问答式的方式建立连接

  1. 第一次握手: A向B发送了一段数据(包含了SYN,全称同步序列号,这是请求建立握手的信息),然后呢,A问了B一个问题,说:”B,你想用哪个同步序列号作为起始字段的数据包回复我呢?”
  2. 第二次握手: B收到了A的请求,B呢也没闲着,他做了两件事,首先,它回复A说:”我收到你的请求了,这是我的ACK+SYN”,然后呢,他也问了A一个问题:”你要用哪个序列号作为起始字段回应我呢?”
  3. 第三次握手: A收到了B的响应,说:”我已经收到了你的回复,现在我要开始真正传输数据了”

相对于UDP协议, 从上面的过程可以看出, 基于TCP协议的所建立的连接是安全可靠的, 在传输数据之间保证两者之间都是健康存在的. 而UDP截然相反,面向无连接,发送端可不管接收端是否健康,只管发送自己的数据包,让数据包根据自己身上的地址去找接受自己的人,要是接收端的程序已经挂掉了,这样数据包也就丢失了.

仅仅是上面的三次握手,数据的传输就一定是安全的吗? 假如三次握手之后,发送端发送出了异常的数据呢? 当然不是,进行数据交互的双方存在确认应答机制 如下图:

当接收端接受到数据后,会告诉发送端自己所期望的下一个数据序号时,这个机制称为确认应答机制,一旦发送端收到收到某个确认应答之后,又连续接到了三个相同的确认应答的信号,那么发送端就知道了发送出现了异常,于是重新根据确认应答的信号进行重新发送

四次挥手

A B 完成了数据的传输后,通过彼此之间的四次挥手,告诉彼此,本次连接正常结束

  1. 第一次挥手: 作为发送端的A,它发送完了数据之后把FIN(希望断开连接的标志)置为1,告诉B,我要准备断开连接了
  2. 第二次挥手: B收到了A发过来的请求断开连接的请求,把ACK置为1,告诉A,我知道你的请求了
  3. 第三次挥手: B向A提出关闭连接的请求,将FIN置为1
  4. 第四次挥手: A接受到B的确认关闭信息,把ACK置为1,告诉B双方的连接到此结束

为什么握手需要三次,但是挥手需要四次呢?

三次握手与四次挥手相比,后者多出来了一次向发送端的发送确认断开的会话,当客户端请求断开的时候,服务端仅仅是回复他,自己收到请求的,但是它不会立即断开,它会等本轮发送的数据包完全发送过去才会断开连接.接着,当全部数据发送过去之后,服务端再次向客户端发送FIN+ACK 告诉它,可以断开了,于是就多了一次挥手

为什么不能进行两次握手连接呢?

两次握手少了一次确认机制,假设依然是A,B进行IO数据交互,同样是A先发起请求,A对B说,老哥,我想问你要点数据,这是我的SYN ,B接收到了,跟A说,好的老弟,这是我的应答分组序号, 然而,B发送给A的消息丢包了,A并没有建立和B的连接,但是B却认为A已经ok了,于是B开始发送数据, 发送给A的数据全部被A忽略掉,B就出现了数据发送的超时,再重新发送就出现了死锁的现象

点击进入:参考链接


HTTP协议(Hyper Text Transfer Protocol)

  • http协议是应用层的协议,所有的www文件全部遵循这个协议
  • HTTP协议的底层使用的TCP/IP协议

    也就是说,在Java中那些web服务器底层使用的是SocketServerSocket 去和浏览器发起的HTTP请求进行交互

历史版本

http 1.0 服务器返回了客户端的信息后,连接直接断掉

http 1.1 服务器返回客户端的信息后,连接依然保持着

两个部分

下面主要是介绍两种协议的数据格式,以及各自的特点

  1. 请求协议
  2. 响应协议:

  • 请求行: 方法(GET/POST) ,URL, 协议/版本
  • 请求头:(Request Header)
  • 请求正文: (请求正文一般是POST的内容,或者是上传文件的时候,携带的文件的内容)

GET:

  1. 在地址栏上拼接数据(所以它会有安全隐患),一般想从服务器获取数据,会用GET

  2. 携带的数据量有限,一般是1kb左右

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
下面的一段是浏览器的请求信息, 分为三部分

// 请求行 GET: 请求方式 请求路径/login 请求参数: ?username=zhangsan&age=123 协议:HTTP/1.1
GET /login?username=zhangsan&age=123 HTTP/1.1
// 请求头
Host: localhost:9999
// 连接方式,保持连接
Connection: keep-alive
// 缓存控制: no-cache 表示每次请求越过缓存,直接从服务器获取数据
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36
// 表示客户端告诉服务端自己支持接收什么类型的数据
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
// 告诉服务器,我们的浏览器支持什么类型的加密算法
Accept-Encoding: gzip, deflate, br
// 支持的语言和编码
Accept-Language: zh,en;q=0.9,zh-CN;q=0.8
Cookie: Idea-9a19dbcd=4a7969e9-f4db-4e10-aa71-f62f0a2168d4; Webstorm-9d134285=fbf822dc-0178-401c-b371-47dc0dd1f169

// 请求体

POST:

  1. 数据是用流的方式写出去的,不会在地址栏显示.
  2. 提交给服务器的数据会在请求体里面,一般是没有大小限制的,POST提交数据的方式,有一个属性叫做:Content-Length: XXX 标记本次提交的请求体的大小
  3. 请求头和请求体之间存在一个换行符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 请求行
POST /register HTTP/1.1

// 下面到情最下的空格之前,都是请求头
// 主机地址
Host: localhost:9999
// 用户代理,向客户端表示来访的客户端的信息,(IE8 9 等),服务端会根据不同的用User-Agent 返回适应客户端的界面
User-Agent: insomnia/6.5.4
Cookie: LY_TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJpZCI6MjksInVzZXJuYW1lIjoiYWRtaW4iLCJleHAiOjE1NTI2MzM2NTF9.FQujeLEJui5wwNLMhJSLKsVOuoZoXETpVAA3L-B35SESOUpaIo0WMriZoTaYiN-R_wokYbXcHXkYfbealbvOa5cX_fheiKmlu67-4HqWHYT_po-F-2PMajN7awHkX9R3Zuc1NqxVmmhqJ0Wb1w_lw1mEAj8CWV8yZZoVbE9525g
// 请求的体的类型: application/json 表示json数据 application/x-www-form-urlencoded 表示经过urlencoded编码的form表单
Content-Type: application/json
Accept: */*
// 数据的长度
Content-Length: 17

// 请求体
{"name":"张三"}

响应协议:

  • 状态行: 协议/版本 状态码
  • 响应头(Response Header)
  • 响应正文
1
2
3
4
5
6
7
8
9
响应行
HTTP/1.1 200 OK
响应头
Server: server-name // 服务器的类型
Content-Type: text/html;charset=utf-8 // 响应给客户端的内容
Content-Length: XXX // 响应内容的长度
Date: XXX // 响应日期
响应体
XXX // 响应体

常见的响应:

1、状态行格式如下:
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息–表示请求已接收,继续处理
2xx:成功–表示请求已被成功接收、理解、接受
3xx:重定向–要完成请求必须进行更进一步的操作
4xx:客户端错误–请求有语法错误或请求无法实现
5xx:服务器端错误–服务器未能实现合法的请求
常见状态代码、状态描述、说明:
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden //服务器收到请求,但是拒绝提供服务
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器发生不可预期的错误
503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
eg:HTTP/1.1 200 OK (CRLF)