1. TCP/IP网络模型有几层?
1. 应用层
最上层我们能直接接触到的就是应用层,在不同设备需要通信的时候,应用要把数据传给下一层, 也就是传输层。所以应用层只需要提供应用功能,比如HTTP、FTP、DNS等。
2.传输层
传输层是为应用层提供网络支持的。
在传输层会有两个传输协议,分别是TCP
和UDP
。
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地址和子网掩码进行按位与运算
,就可以得到网络号和主机号。
在寻址的过程中,先匹配到相同的网络号(同一子网),才会去找对应的主机。
除了寻址,IP协议还有一个重要的能力就是路由
。路由会根据IP寻址的目的地选择路径,将数据包转发给对应的网络。
4. 网络接口层
生成了 IP 头部之后,接下来要交给网络接口层(Link Layer)在 IP 头部的前面加上 MAC 头部,并封装成数据帧(Data frame)发送到网络上。
总结
综上所述,TCP/IP 网络通常是由上到下分成 4 层,分别是应用层,传输层,网络层和网络接口层。
每一层的封装格式:
2. HTTP常见面试题
2.1 HTTP是什么?
HTTP是超文本 传输 协议。
- 协议:HTTP是用在计算机世界里的一种协议,它使用两个以上的计算机交流通信能够理解的语言,以及各种控制和错误处理方式。
- 传输:HTTP是一个双向协议。它是专门在两点间传输数据的约定和规范。
- 超文本:HTML就是常见的超文本。 所以综上所述,HTTP是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。
2.2 HTTP常见的状态码
2.3 HTTP常见的字段
- Host字段:指定服务器的域名,例如
www.A.com
- Content-Length:返回数据的长度
- Connection:常用语客户端也奥球服务器使用TCP持久连接,以便复用。(在HTTP/1.1中默认都是持久连接,但是为了兼容老版本,需要指定
Connection
字段为Keep-Alive
) - Content-Type:数据格式
- 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
的时候,这个就是服务器告诉浏览器可以使用本地缓存的资源,这种就是协商缓存。那么是怎么协商的呢?
- 请求头中
If-Modified-Since
字段和Last-Modified
字段。
Last-Modified
字段表示响应资源的最后修改时间。If-Modified-Since
字段:当服务器收到请求后,发现有该字段,则会去与Last-Modified
字段对比,如果被改过则返回最新200;如果没被修改,则304走缓存。
- 请求头部的
Last-Modified
字段和响应头的ETag
字段。
- 响应头的
ETag
:唯一标识,就和身份证一样。 - 请求头的
Last-Modified
:当资源过期时,浏览器发现ETag,则再次像服务器发送请求,这时会将请求头Last-Modified
的值设为ETag
。服务器说道请求后进行比对,变化则200,没变则304。
上述两种方式,一个是比时间,一个是比唯一标识。相对来说后者更加准确,毕竟时间可以篡改。
并且我们要注意,协商缓存一定是配合强制缓存的Cache-Control
字段来使用的,只有在强制缓存未命中时,才能发起协商缓存的请求。
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 区别
- HTTP明文传输,有安全问题。HTTPS解决了,可以加密传输。
- HTTP的端口是80,HTTPS的端口是443
- 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 提高了什么性能
- 性能改进:
- 使用长连接的方式,改善了性能开销
- 支持管道网络传输,减少整体响应时间。
- 性能瓶颈:
- 头部未经压缩就发送,头部信息多延迟大,只能压缩body部分。
- 每次发送相同的头部,造成性能浪费。
- 服务器按顺序响应,造成队头阻塞
- 不能控制请求优先级。
- 只能客户端请求,服务器响应。
2.8.2 HTTP/2 做了什么优化?
- 性能改进:
- 头部压缩:如果你发送多个请求的头部是一样的,那么协议会帮你去重。用的是
HPACK
算法:在客户端和服务器同时维护一张头信息表,里面包含所有的字段+索引号,只发送索引号,速度提升明显。 - 二进制:报文采取二进制格式,头信息和数据体统称为帧(frame)头信息帧和数据帧,增加了数据传输效率。
- 数据流:请求可并发可乱序,可指定优先级。
HTTP/2的每个请求或响应的所有数据包,称为一个数据流(
Stream
)。每个数据流标记着一个独一无二的编号(StreamId
),不同的Stream的帧是可以乱序发送的,所以帧的头部会带有StreamId信息,接收端通过ID有序组装成HTTP消息。
客户端和服务端都可以建立Stream
,Stream ID
也是有区别的,客户端奇数,服务端偶数。
- 多路复用:可以并发多个请求或响应且不用按照顺序一一对应,不再出现队头阻塞,降低延迟,提高连接利用率。
- 服务器推送:服务器可以主动的向客户端发送消息。
- 性能缺陷:
- TCP的队头阻塞问题: HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
如果packet3在网络中丢失了,那么4-6只能等3重传后,才能读取到数据。
2.8.3 HTTP/3 做了什么优化?
HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!
UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。QUIC有以下三个特点:
- 无队头阻塞:QUIC连接上的Stream之间没有依赖,所以某个流丢包不会影响其他流。
- 更快的连接:HTTP/3在传输数据前只需要1RTT来确认双方的[ID]。
- 连接迁移:通过连接ID来标记通信的两个端点,实现无缝连接。
3. TCP的三次握手和四次挥手
3.1 建立连接的三次握手
- 第一个SYN报文:
客户端随机初始化序号置于TCP头部,同时把
SYN
的标志位置为1
,表示SYN
报文。接着发给服务端,表示发起连接。
- 第二个SYN+ACK报文
服务器在收到客户端的
SYN
报文后,也开始随机生成自己的序列号置于TCP头部,然后把TCP头部的确认应答号
填入序号+1
,接着把SYN
和ACK
的标志位置为1
。最后把该报文发送给客户端。
- 第三个ACK报文
客户端在收到服务器的报文后,还需要像服务器回应最后一个应答报文了,将TCP头部的
ACK
标志位置为1
,接着在确认应答号位置填入服务端的序列号+1
。最后把报文发送给服务端。这次报文可以携带客户到服务端的数据
3.1.1 为什么不是两次或者四次握手?
- 四次握手:其实第二步和第三步可以优化成一步,所以就成了三次握手。
- 两次握手:
-
无法可靠的同步双方序列号 在TCP通信中,序列号是可靠传输的一个关键因素,如果仅仅两次握手就不能确定客户端是否收到了服务器的序列号。
-
无法避免历史重连,造成性能浪费(首要原因) 当客户端发送了第一个seq=90的报文被网络阻塞之后,服务器没有收到,接着客户端就又发送了一个seq=100的报文,但是seq=90的先到达,看看三次握手是怎么避免历史连接的。
如果是两次握手,那么在第一次的90到达时就会完成连接。当新的100过来时,就又开始了一轮新的连接,这样历史连接依旧完成,并且造成了资源的浪费。
3.1.2 为什么每次TCP连接的初始序列号要求不一样呢?
如果初始序列号一致就可能出现历史报文被服务器接收。
3.2 断开连接的四次挥手
- 客户端打算关闭连接,此时会发送一个 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应答报文,因为服务器通常需要等待完成数据的发送和处理,所以服务端的ACK
和FIN
一般都会分开发送。
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过多的话,就会导致资源端口被占用,占满的话就无法创建新的连接。