HTTTTTTTTTTTP

160 阅读16分钟

1. TCP/IP网络模型有几层?

1. 应用层

最上层我们能直接接触到的就是应用层,在不同设备需要通信的时候,应用要把数据传给下一层, 也就是传输层。所以应用层只需要提供应用功能,比如HTTP、FTP、DNS等。

2.传输层

传输层是为应用层提供网络支持的。

在传输层会有两个传输协议,分别是TCPUDP

TCP的全称为传输控制协议,大部分应用正是使用的TCP传输层协议,比如HTTP应用层协议。TCP相比UDP多了很多特性,比如流量控制、超时重传等,这些都可以保证数据能可靠的传给对方。

UDP只负责发送数据包,它的实时性相对更好,传输效率也高。

应用需要传输的数据很大时,如果直接传输不好控制。当大小超过MSS(TCP最大报文段长度),就要将数据包分块,我们把每个分块都称为一个TCP段

当作为接收方时,传输层负责将数据包传给应用层,但是一台设备可能有多个应用在接收/传输数据,需要一个编号来区分,这就是端口

3. 网络层

实际上我们的网络环节是非常复杂的,传输层的设计理念是简单、高效。也就是说我们不希望传输层协议处理太多事情,而实际的传输功能就是网络层

网络层最常使用的是 IP 协议(Internet Protocol),IP 协议会将传输层的报文作为数据部分,再加上 IP 包头组装成 IP 报文。

那么我们是如何找到对方的呢?

我们一般用IP地址给设备进行编号,对于IPv协议,IP地址共32位,分成了四段,每段8位。但是对所有的IP地址进行寻址太麻烦了,所以我们要将IP地址分成两种意义:

  • 网络号:负责标识该IP是属于哪个子网的
  • 主机号:负责标识统一子网下的不同主机

将IP地址和子网掩码进行按位与运算,就可以得到网络号和主机号。

image.png 在寻址的过程中,先匹配到相同的网络号(同一子网),才会去找对应的主机。

除了寻址,IP协议还有一个重要的能力就是路由。路由会根据IP寻址的目的地选择路径,将数据包转发给对应的网络。

4. 网络接口层

生成了 IP 头部之后,接下来要交给网络接口层Link Layer)在 IP 头部的前面加上 MAC 头部,并封装成数据帧(Data frame)发送到网络上。

总结

综上所述,TCP/IP 网络通常是由上到下分成 4 层,分别是应用层,传输层,网络层和网络接口层

image.png 每一层的封装格式:

image.png

2. HTTP常见面试题

2.1 HTTP是什么?

HTTP是超文本 传输 协议。

  • 协议:HTTP是用在计算机世界里的一种协议,它使用两个以上的计算机交流通信能够理解的语言,以及各种控制和错误处理方式。
  • 传输:HTTP是一个双向协议。它是专门在两点间传输数据的约定和规范。
  • 超文本:HTML就是常见的超文本。 所以综上所述,HTTP是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。

2.2 HTTP常见的状态码

2.3 HTTP常见的字段

  1. Host字段:指定服务器的域名,例如www.A.com
  2. Content-Length:返回数据的长度
  3. Connection:常用语客户端也奥球服务器使用TCP持久连接,以便复用。(在HTTP/1.1中默认都是持久连接,但是为了兼容老版本,需要指定Connection字段为Keep-Alive
  4. Content-Type:数据格式
  5. Content-Encoding:数据的压缩方法(gzip,deflate等)

2.4 GET和POST请求的区别

  • GET请求 从服务器获取指定的资源。请求的参数一般写在URL中;URL规定只能支持ASCII,所以GET请求的参数只允许ASCII字符;而且浏览器对于URL的长度也有闲置。
  • POST请求 根据请求body对指定的资源做出处理。请求的参数一般写在body中,body的数据可以是任何格式的数据,只要客户端和服务端协商好即可;浏览器对于body的大小也没有限制。
  • GET和POST方法都是安全和幂等的吗?

安全:请求方法不会破坏服务器上的资源

幂等:多次执行相同操作,结果相同。

从RFC规范定义和语义来看

  • GET方法就是安全且幂等的。所以可以对GET请求的数据做缓存,这个缓存可以做到浏览器本身,也可以做到代理上。
  • POST方法是不安全且不幂等的。所以浏览器一般不会缓存POST请求。

2.5 HTTP缓存技术

2.5.1 强制缓存

强缓存--浏览器判断是否国企,如果没有过期直接使用本地缓存。

强缓存是利用下面这两个响应头实现的

  • Cache-Control,过期的相对时间
  • Expires,过期的绝对时间 如果响应头中同时有上述两个字段,则Cache-Control的优先级要高于Expires

一般建议使用Cache-Control设置过期时间的大小,当浏览器再次访问服务器的该资源时,会先判断相对时间与请求时间,如果未过期则使用本地缓存;已过期则再次发送请求,更新Cache-Control

2.5.2协商缓存

当我们获取到的状态码是304的时候,这个就是服务器告诉浏览器可以使用本地缓存的资源,这种就是协商缓存。那么是怎么协商的呢?

  1. 请求头中If-Modified-Since字段和Last-Modified字段。
  • Last-Modified字段表示响应资源的最后修改时间。
  • If-Modified-Since字段:当服务器收到请求后,发现有该字段,则会去与Last-Modified字段对比,如果被改过则返回最新200;如果没被修改,则304走缓存。
  1. 请求头部的Last-Modified字段和响应头的ETag字段。
  • 响应头的ETag:唯一标识,就和身份证一样。
  • 请求头的Last-Modified:当资源过期时,浏览器发现ETag,则再次像服务器发送请求,这时会将请求头Last-Modified的值设为ETag。服务器说道请求后进行比对,变化则200,没变则304。

上述两种方式,一个是比时间,一个是比唯一标识。相对来说后者更加准确,毕竟时间可以篡改。

并且我们要注意,协商缓存一定是配合强制缓存的Cache-Control字段来使用的,只有在强制缓存未命中时,才能发起协商缓存的请求。

image.png

2.6 HTTP特性

2.6.1 HTTP的优点

  • 简单:基本的报文格式是header+body,头部信息key-value的简单文本形式,非常容易理解。
  • 灵活:HTTP协议中各类请求的方法、URI/URL、头部字段等都没有被锁死,都允许开发人员自定义和扩充。
  • 可以跨平台

2.6.2 HTTP的缺点

  • 无状态: 无状态的好处:因为服务器不会记忆HTTP的状态,所以不需要额外记录信息,减轻服务器的负担。

无状态的坏处:没有记忆力可想而知,会做很多重复性的工作。

对于无状态的解决,其中比较简单的方法就是用Cookie技术。

相当于在客户端第一次请求时,服务器会给客户端一个身份证,在后续该客户端请求时会携带身份证,服务器认得了就ok了。

  • 明文传输: 明文传输的好处不用多说,调试起来轻轻松松。但是信息裸奔,直接大寄特寄。
  • 不安全:

明文传输,内容不安全。 不验证同新方的身份,可能遭到伪装。 无法证明报文完整,可能遭到篡改。

上述的安全问题,可以用HTTPS的方式解决。

2.6.3 HTTP的性能如何

  • 长连接: 早起HTTP/1.0性能上的很大的问题就是,每次发起请求都要新建一次TCP连接。为了解决上述问题,HTTP/1.1中提出了长连接的通信方式,即未提出明确的断开连接,则保持TCP连接状态。
  • 管道传输: 即不用等服务端返回就发送下一个请求,但是服务端必须按照接收的顺序发送响应,那么一旦某一个请求响应时间很长,就会发生队头阻塞。

注意:实际上管道技术默认不开启,并且浏览器基本不支持...

  • 队头阻塞 当第一个请求的响应时间过长时,会导致后面的也被阻塞,这就叫队头组设。

2.7 HTTP与HTTPS

2.7.1 区别

  1. HTTP明文传输,有安全问题。HTTPS解决了,可以加密传输。
  2. HTTP的端口是80,HTTPS的端口是443
  3. HTTPS协议需要向CA申请数字证书。

2.7.2HTTPS如何解决了上述HTTP的问题

HTTPS在HTTP和TCP层之间加了SSL/TLS协议:

  • 信息加密 使用混合加密的方式来保证信息的机密性。那么具体是混合了哪两种呢?

非对称加密是在通信建立前,对于公钥和私钥进行安全交换。公钥可以随意分发,私钥需要保密。 对称加密是在通信过程中全部使用会话秘钥。运算速度快。

  • 校验机制 摘要算法+数字签名。为保证内容不被篡改,我们需给内容一个指纹,然后对方收到后根据内容计算出一个指纹,如果相同则未篡改。

在计算机中,会用到摘要算法(哈希函数)来计算内容的哈希值,也就是[指纹]。但是这种方法有个bug,他只能验证消息完整,但不能验证来源。就是人家可以连内容 + 哈希值一起给改了。

那么这种情况我们可以也使用类似上面的非对称加密法。这样我们可以利用私钥和公钥进行加解密出来一个哈希值,这样进行对比就能确定来源了。

  • 身份证书 上面两步我们已经确定了消息的完整和来源的可靠,但是到底是谁发的我们还不知道。那么我们就需要一个数字证书来验证身份的真实性。

2.7.3 HTTPS是如何建立连接的?交互了什么?

2.8 HTTP/1.1 、HTTP/2、HTTP/3 演变

2.8.1 HTTP/1.1相比HTTP/1.0 提高了什么性能

  • 性能改进:
  1. 使用长连接的方式,改善了性能开销
  2. 支持管道网络传输,减少整体响应时间。
  • 性能瓶颈:
  1. 头部未经压缩就发送,头部信息多延迟大,只能压缩body部分。
  2. 每次发送相同的头部,造成性能浪费。
  3. 服务器按顺序响应,造成队头阻塞
  4. 不能控制请求优先级。
  5. 只能客户端请求,服务器响应。

2.8.2 HTTP/2 做了什么优化?

  • 性能改进:
  1. 头部压缩:如果你发送多个请求的头部是一样的,那么协议会帮你去重。用的是HPACK算法:在客户端和服务器同时维护一张头信息表,里面包含所有的字段+索引号,只发送索引号,速度提升明显。
  2. 二进制:报文采取二进制格式,头信息和数据体统称为帧(frame)头信息帧和数据帧,增加了数据传输效率。
  3. 数据流:请求可并发可乱序,可指定优先级。 HTTP/2的每个请求或响应的所有数据包,称为一个数据流(Stream)。每个数据流标记着一个独一无二的编号(StreamId),不同的Stream的帧是可以乱序发送的,所以帧的头部会带有StreamId信息,接收端通过ID有序组装成HTTP消息。

客户端和服务端都可以建立StreamStream ID也是有区别的,客户端奇数,服务端偶数。

  1. 多路复用:可以并发多个请求或响应且不用按照顺序一一对应,不再出现队头阻塞,降低延迟,提高连接利用率。
  2. 服务器推送:服务器可以主动的向客户端发送消息。
  • 性能缺陷:
  1. TCP的队头阻塞问题: HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。

image.png

如果packet3在网络中丢失了,那么4-6只能等3重传后,才能读取到数据。

2.8.3 HTTP/3 做了什么优化?

HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!

UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。QUIC有以下三个特点:

  1. 无队头阻塞:QUIC连接上的Stream之间没有依赖,所以某个流丢包不会影响其他流。
  2. 更快的连接:HTTP/3在传输数据前只需要1RTT来确认双方的[ID]。
  3. 连接迁移:通过连接ID来标记通信的两个端点,实现无缝连接。

3. TCP的三次握手和四次挥手

3.1 建立连接的三次握手

image.png

  1. 第一个SYN报文: 客户端随机初始化序号置于TCP头部,同时把SYN的标志位置为1,表示SYN报文。接着发给服务端,表示发起连接。

image.png

  1. 第二个SYN+ACK报文 服务器在收到客户端的SYN报文后,也开始随机生成自己的序列号置于TCP头部,然后把TCP头部的确认应答号填入序号+1,接着把SYNACK的标志位置为1。最后把该报文发送给客户端。

image.png

  1. 第三个ACK报文 客户端在收到服务器的报文后,还需要像服务器回应最后一个应答报文了,将TCP头部的ACK标志位置为1,接着在确认应答号位置填入服务端的序列号+1。最后把报文发送给服务端。这次报文可以携带客户到服务端的数据

image.png

3.1.1 为什么不是两次或者四次握手?

  • 四次握手:其实第二步和第三步可以优化成一步,所以就成了三次握手。

image.png

  • 两次握手:
  1. 无法可靠的同步双方序列号 在TCP通信中,序列号是可靠传输的一个关键因素,如果仅仅两次握手就不能确定客户端是否收到了服务器的序列号。

  2. 无法避免历史重连,造成性能浪费(首要原因) 当客户端发送了第一个seq=90的报文被网络阻塞之后,服务器没有收到,接着客户端就又发送了一个seq=100的报文,但是seq=90的先到达,看看三次握手是怎么避免历史连接的。

image.png

如果是两次握手,那么在第一次的90到达时就会完成连接。当新的100过来时,就又开始了一轮新的连接,这样历史连接依旧完成,并且造成了资源的浪费。

3.1.2 为什么每次TCP连接的初始序列号要求不一样呢?

如果初始序列号一致就可能出现历史报文被服务器接收。

image.png

3.2 断开连接的四次挥手

image.png

  • 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。
  • 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。
  • 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。
  • 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
  • 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态
  • 服务器收到了 ACK 应答报文后,就进入了 CLOSED 状态,至此服务端已经完成连接的关闭。
  • 客户端在经过 2MSL 一段时间后,自动进入 CLOSED 状态,至此客户端也完成连接的关闭。

3.2.1 为什么是四次挥手?

因为客户端和服务端都需要发送FIN包并且发送ACK应答报文,因为服务器通常需要等待完成数据的发送和处理,所以服务端的ACKFIN一般都会分开发送。

3.2.2 每一次挥手丢失会发生什么?

  • 第一次和第二次 第一次和第二次挥手丢失,都会导致客户端接受不到ACK,所以客户端出发超时重传机制,重新传FIN报文,重发次数由tcp_orphan_retries参数控制。超过次数不再发送FIN报文,直接close。
  • 第三次和第四次 这两次挥手丢失会导致服务器端接收不到ACK,所以服务器端会重新发送FIN报文。

3.2.3 TIME_WAIT等待时间为什么是2MSL?长了或者短了有什么问题?

  • MSL 是啥意思? MSL 是报文最大生存时间,2个MSL正好是数据包被接收+响应的包的时间。
  • 太短或者没有 如果TIME_WAIT太短或者直接没有该状态,就有可能当连接关闭后新开的连接接收到历史的报文,造成数据混乱。

如果客户端给服务端的ACK响应报文丢失了,那么当服务端重传的时候,他已经是CLOSE状态了,这样就会导致一个RST错误。

  • 太长 TIME_WAIT过多的话,就会导致资源端口被占用,占满的话就无法创建新的连接。