NIO编程TCP/IP协议

HTTP详解

2021-08-11  本文已影响0人  小驴小驴

HTTP协议是“看不着、摸不着”的。因为在Java语言中,有太多的HTTP相关的库,如:HTTPClient、HTTPUrlConnection、Spring的RestTemplete等。因此在某种程度上从事Java相关的开发人员很难需要去深扒HTTP协议,而基本上都属于会用就好的状态。

编写本文的思路正如下面的文章目录。

目录

一、HTTP简介

HTTP中文名称是超文本传输协议(英文:HyperText Transfer Protocol),HTTP是基于 TCP/IP 协议之上的应用层协议,HTTP是万维网数据通信的基础。

因此,在HTTP建立之前,需要先等客户端与服务端建立TCP连接。

二、什么是协议

在了解具体的HTTP协议之前,最好还是先了解什么叫协议,这对之后的学习其它协议肯定会有帮助。

2.1 协议的定义

协议,网络协议的简称,网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定,计算机之间才能相互通信交流。它的三要素是:语法、语义、时序。

为了使数据在网络上从源到达目的,网路通信的参与方必须遵循相同的规则,这套规则称为协议(protocol),它最终体现在网络上传输的数据包的格式。

协议往往分为几个层次进行定义,分层定义是为了使某一层协议的改变不影响其他层次的协议。

备注:以上文字来源于百度百科

三、Wireshark网络抓包工具

Wireshark是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换。

在学习HTTP协议的过程中,因为HTTP协议的是看不见摸不着的,这给学习带来一定的难度。因此有必要用Wireshark抓包工具抓取一个HTTP协议下来观察。

Wireshark官网地址:https://wireshark.en.softonic.com/
先看一下Wireshark的界面:

1.Wireshark1.png

显而易见:Wireshark抓包界面中分为顶部的菜单栏、过滤栏、上、中、下五个部分;

四、HTTP协议

4.1 前置知识

在HTTP协议中,有很多的符号如:\n\r等,而也正是因为这些符号对HTTP协议解决拆包、粘包提供了基础

标识 ASCII 描述 字符
CR 13 回车 \n
LF 10 换行 \r
SP 32 空格
COLON 58 冒号 :

4.2 请求协议结构

4.2.1 描述

HTTP请求体中包含三个部分:① 请求行、② 请求头(Header)、③ 请求正文(Body)

0.HTTP协议Request透视图.png

概括为文字如下:

4.2.2 抓包查看

2.Wireshark2.png

4.3 响应协议结构

4.3.1 描述

HTTP响应体中包含三个部分:① 状态行、② 响应头(Header)、③ 响应正文(Body)

3.HTTP协议Response透视图.png

概括为文字如下:

4.3.2 抓包查看

4.Wireshark4.png

看到这里,有的小伙伴可能会提出问题:

问:在上图中[响应头]与[响应正文]之间是什么数据呢?

答:这些数据是Wireshark为了辅助展示出的一些指标数据。实际上,在网络包中并没有这些数据,这里对比一下最下面的方块,看一下网络包中真正的数据。

问:在网络分层中,Hypertext Transfer Protocol已经是网络模型中的应用层了,那为什么上图的抓包中,最下面还有一层:Line-base text data:text/plain(1 lines)

答:这个问题的答案其实和上一个问题的答案一致,这只是Wireshark为了展示的更加人性化,将数据抽离在了该层展示低而已,注意看最下面的红色框框,在Header结束之后就是两个CRLF,紧接着就是数据(hello world!)了。

4.4 分包传输

在HTTP协议中,除了将数据放在一个包中一次性发出,还可以通过分包方式将一个大批数据分在多个数据包中进行传输。需要注意的是,分包传输使用的也是同一个Socket连接。
在Header中通过Transfer-Encoding: chunked进行指定,该KV与Content-Length只能同时出现一个。
需要注意的是:在HTTP1.0版本协议中不支持分包。在HTTP1.1之后开始支持分包。

4.4.1 结构图

5.chunked.png

4.4.2 优点

4.4.3 缺点

4.4.4 抓包查看

6.Wireshark6.png

4.5 KeepAlive

HTTP协议如果不做特殊处理都是一种短连接,即为一次会话建立TCP/IP之后,客户端与服务端基于TCP/IP的连接之上通过HTTP协议完成会话后,连接也会被服务端断开。下一次的HTTP请求,还是需要为这个请求进行三次握手创建TCP连接,用完之后还需要四次挥手断开TCP连接,这大大减少了传输效率。

而KeepAlive的产生就是为了弥补上述的不足。

HTTP1.0版本中需要在Header中加入Connection: keep-alive来指定会话完毕之后不立即断开连接,而是有一定的复用时间。HTTP1.1版本中,默认开启该配置:Connection: keep-alive

4.5.1 Tomcat对KeepAlive的支持

4.5.2 TCP协议与HTTP协议中的KeepAlive区别

需要注意的是:TCP协议中也有KeepAlive参数,但是与HTTP的KeepAlive还是有区别的;

4.5.3 如何复用长连接

首先需要了解的是,复用到底复用的是什么,看了上面的介绍,短连接中的每次请求都需要先进行TCP的连接导致TCP链路无法复用,因此这里的复用其实是针对TCP链路的复用。

可以配合连接池,如HttpClient就对长连接具有管理的功能,注意这里的管理肯定是针对长连接了,短连接压根就无法复用。

4.5.4 如何关闭长链接

当TCP连接需要关闭时,只需要在Header头中添加Connection: close即可。

4.5.5 疑问待解决

Tomcat9版本中默认KeepTimeout为20s,我也查看了一下SpringBoot对于Tomcat的配置,发现SpringBoot没有对Tomcat参数做调整,至少KeepTimeout用的就是Tomcat默认值。

那么在这样的情况下,KeepTimeout最终应该为20s才对,但是在抓包过程中却发现其值为60s.

抓包如下:


7.Wireshark7.jpg

4.5.6 从JVM层面判断连接是否复用

TODO

五、HTTP协议如何解决TCP的粘包与拆包

TCP协议,数据传输都是stream式的,数据之间是没有流边界的,在这样情况下自然就会出现粘包与拆包的问题。那么基于TCP之上的HTTP协议当然也会面临这样的问题,那它是如何解决的呢?

了解了HTTP协议的结构之后,解决粘包拆包的问题就迎刃而解了。

HTTP的请求与响应,对于请求行、请求头、响应行、响应头而言,都可以通过CRLF与空格作为流的边界进行读取。

对于请求正文与响应正文而言,他们的字节长度在Header中的Content-Length中定义,假若,Header中没有Content-Length属性,取而代之的是Transfer-Encoding: chunked,那么就读取每一个chunk的size,继而再读取size个byte,知道读取到last-chunk的size为0。

上一篇 下一篇

猜你喜欢

热点阅读