面试?一篇就搞定!!史上最全TCP面试题 + 解答!

运输层是面向通信部分的最高层,同时也是用户应用功能中的最底层,主要是向下封装通信部分、对接应用层完成分用复用这两个主要功能,运输层是通常开发中接触到的最底层。在 TCP/IP 协议栈中有两种重要的运输层协议 UDPTCP,同时 TCP 也是应用层 HTTP 协议的基础。

本篇以面试问题为导向,用通俗易懂的语言进行总结回答。

温故而知新,可以为师矣。

本篇文字较多:先收藏,不迷路哦!有帮助的话,别忘了点赞+关注!

上一篇:《面试必考问题一文搞定:HTTP和HTTPS?TLS的工作流程?》

插个题外话,推荐一本书《图解HTTP》,作为一名菜鸟觉得这本书非常有趣,哪怕是作为睡前读物也是可以的。不得不吐槽一下学校用的谢希仁第七版的计网教材,真的又臭又硬。(当然了之后的深入学习还是要沉下心来去细啃一下)

热身一下:说说 TCP 和 UDP 的区别?

TCP(传输控制协议):面向连接以字节流的方式进行传输,提供可靠服务,适用于文件传输、邮件传输、聊天消息等需要可靠传输的常见,首部 20~60 字节。通信双方需要经过三次握手后才能建立 TCP 连接进行通信,通信完成后还需要四次挥手断开连接。并且 TCP 不支持多播和广播服务。

UDP(用户数据报协议):无连接以数据报文段的方式进行传输,提供非可靠传输服务,但是传输速度比 TCP 协议快,占用资源比 TCP 协议少,适用于要求通信速度的场景如域名转换、视频流、直播流等等,首部 8 字节。仅仅提供了校验和来保证报文的完整性,如果校验失败,直接丢弃,不做任何处理。

关于 TCP 连接的建立和关闭有了解过么?

TCP 协议为了保证通信服务的可靠性,采用三次握手的策略来建立可靠的通信信道,数据传输完成后通过四次挥手的策略来关闭连接。

为什么需要三次握手才能建立连接?

三次握手的过程大致如下图:
在这里插入图片描述

出自《图解HTTP》 PS:下文用客户端和服务端来表述上图中的发送端和接收端。

  1. 第一次握手:发送端(客户端)发送带有 SYN 标志的数据包给接收端(服务端),接收端接收到这个数据包之后,服务端知道了客户端发送功能正常,同时也知道了服务端接收功能正常
  2. 第二次握手:服务端发送带有 SYN/ACK 标志的数据包给客户端,客户端接收到这个数据包之后,客户端就知道了客户端发送、接受功能都正常服务端发送、接受功能都正常
  3. 第三次握手:客户端发送带有 ACK 标志的数据包给服务端,服务端接收到这个数据包后,服务端知道了客户端发送、接受功能都正常服务端发送、接受功能都正常

至此,三次握手完成,此时的客户端和服务端都确认了:双方的收发功能全部正常

缺少任何一步,都不能使双方成功相互确认收发功能。

为什么不是两次握手呢?为什么客户端还要最终确认一次呢?

为了防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误连接。如果是两次握手,举例如下:

客户端发送了第一个 SYN 标志的连接请求,但是在网络中阻塞滞留了,客户端一直到超时都没有等到来自服务端的确认请求,于是重发了一个 SYN 标志的连接请求,这次顺利完成两次握手建立了连接、传输数据、关闭连接。一切风平浪静了。。。这时!第一个连接请求姗姗来迟,到达了服务器,经过两次握手建立了一个并不需要的连接,浪费了资源还可能导致不必要的错误。

如果是三次握手策略,当第一个被阻塞滞留报文传送到服务端,虽然服务端对这条无效报文回复了对应的 SYN-ACK 确认报文,但是客户端不会再次发出 ACK 报文,从而让服务器知道客户端并不需要建立这个连接。

服务端为什么要回传 SYN-ACK 应答标志?而不是 ACK 标志?

SYN 是客户端发出的一个握手信号,服务端接收后回传是为了告诉客户端,我要应答的握手信息确实就是你所发送的。

说说四次挥手的过程?

打字好累,我相信看字也不轻松,换换脑子,来画个图吧!
在这里插入图片描述

  1. 第一次挥手:客户端进入 FIN-WAIT-1 阶段,客户端就不再向服务端传输数据了,但是依然可以接受服务端的数据。

  2. 第二次挥手:服务端收到客户端发来的 FIN 标志的关闭连接报文,通知上层应用后向客户端发送 ACK 标志的确认报文,进入 CLOSE-WAIT 阶段。

    客户端收到这个确认报文后,进入 FIN-WAIT-2 阶段,继续接收服务端传输的数据,并等待服务端发送 FIN 标志的关闭连接报文。

  3. 第三次挥手:服务端传输完最后的数据,向客户端发送 FIN 标志的关闭连接报文,并进入 LAST-ACK 阶段,等待客户端最后的确认。

  4. 第四次握手:客户端收到服务端的关闭连接报文后,发出最后的 ACK 标志的确认报文,并进入 TIME-WAIT 阶段,这个阶段会在等待 2MSL(报文最大生存时间) 后释放客户端 TCB(传输控制块) 进入 CLOSED 状态,真正完成关闭连接。

    而服务端收到客户端发来的 ACK 标志的确认报文后,立刻释放服务端 TCB 进入 CLOSED 状态,完成连接关闭。

服务器完全关闭 TCP 连接的时间要比客户端早一些。

客户端完成确认完成后为什么不能立刻释放资源关闭连接?还要等待 2MSL?

等待 2MSL(报文最大生存时间) 是为了确保客户端发送的 ACK 标志的确认报文能够正确到达服务端,如果这个确认报文因为各种问题导致没有到达服务端,服务器会在定时器到期后,重新发送 FIN+ACK 标志的连接关闭报文,而客户端在这个等待的 2MSL 的时间段内可以收到这个服务端重传的报文,从而重新发送 ACK 确认报文,并且重启 2MSL 时间的计时器。

为什么三次握手就可以建立连接,而关闭连接却需要四次挥手呢?

建立连接的时候,服务端监听到建立连接的 SYN 报文后,将 ACK 和 SYN 一起发送给客户端,就可以让客户端知道服务端收到了自己的请求,并且已经做好了建立连接的准备。

关闭连接的时候,服务端收到客户端发来的 FIN 报文后,知道客户端不再发送消息了,于是服务端可以立刻回应一个 ACK 报文,但是服务端此时可能还需要继续发送完最后的数据,只有当服务端发送完最后的数据,才能够向客户端发出自己的 FIN 报文。正是因为关闭连接时 ACK 和 FIN 标志的报文需要分开发送,所以导致关闭连接时需要多发送一次报文。

如果建立连接之后,客户端出现故障了怎么处理的?

为了防止服务器一直等待从而白白浪费资源,TCP 设置了一个保活计时器,服务端每次收到客户端请求之后就会重置保活计时器,如果计时器到期仍没有收到来自客户端的数据,服务器会主动地每隔 75 秒发送一个探测报文,如果连续发送 10 个探测报文客户端仍然没有动静,服务器就会释放资源关闭连接。

除了刚才说的握手挥手,还有其他保证TCP可靠传输的机制么?

接下来部分文字摘自谢希仁的《计算机网络》第七版

tSPuFJ.png

检验和

TCP 报文首部的检验和字段,目的用来校验首部和数据两部分在传输过程中的正确性,如果接收端收到报文后通过检验和计算发现出了差错,TCP 协议会将这个出错的报文段直接丢弃,并且不会进行相应的确认。

ARQ协议

自动重传请求(ARQ)是 OSI 七层模型中数据链路层传输层的一个错误纠正协议,有确认超时两个主要机制,可以在不可靠的传输网络上实现可靠的通信。如果发送方发送消息一段时间后没有收到对应的确认帧,发送方会重新发送这条消息。

停止等待ARQ协议

发送方每发完一个分组就停止发送(暂时保留已发送分组的副本),等待接收方的 ACK 确认帧。如果等待计时器超时后,还没收到 ACK 确认,说明消息没有成功发送,需要重新发送,直至收到对应的确认帧再发送下一个分组。

分组和分组的确认都必须进行编号,这样才能明确哪一个发送出去的分组收到了确认,而且可以检测到重复的分组,重复的分组需要丢弃,但还是需要发送确认。

这么做的优点是协议简单,缺点是信道利用率低、等待时间长。

连续ARQ协议

发送方维持一个发送窗口,所有在发送窗口内的分组都可以连续发送出去,不需要停止等待接收方的确认帧。接收方采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。

这么做的优点是信道利用率高、容易实现,即使分组丢失也不必立刻重传。

缺点是不能向发送方反映出接收方已经确认收到的所有分组信息。例如:发送方发送了 5 个分组,中间的第 3 个分组丢失了,这时接收方只能对前两个分组发出确认收到,发送方无法知道后面三个分组的情况,只好把后面的三个分组都重传一次,这个过程叫做 Go-Back-N(回退 N),表示需要回退回来,重传已经发送过的 N 个分组。

所以当通信线路质量不好时,连续 ARQ 协议会带来负面影响。

流量控制

TCP 使用可变滑动窗口实现流量控制,就是让发送方的发送速率不要太快,要让接收方来得及接受。接收方发送的确认报文中的窗口字段用来控制发送方窗口的大小,从而影响发送方的发送速率。当窗口字段设置为 0 时,发送方不能发送数据。

流量控制往往是点到点通信量的控制,是一个端到端的问题。

拥塞控制

拥塞控制就是为了防止过多的数据注入到网络中,这样就可以是网络中的路由器或链路不至于过载。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。

拥塞控制依然是利用发送方维持的一个拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。

在网络层也可以使路由器采用合适的分组丢弃策略,例如 AQM(主动队列管理) 等,以减少网络拥塞的发生。

TCP 拥塞控制主要涉及四种算法:慢开始、拥塞避免、快重传、快恢复。

慢开始

当最开始发送数据时,因为不知道网络的情况,所以不能立即注入大量的数据到网络中,不然可能会引起网络拥塞。较好的方法是先探测一下,由小到大逐渐增加发送窗口的大小,cwnd 的初始值是 1 ,没经过一个传播轮次,cwnd 就翻倍。

拥塞避免

拥塞避免听名字就很"谨慎",当窗口大小达到一定的门限值/阈值 (ssthresh) 后,就让拥塞窗口 cwnd 缓慢增大,每经过一个往返时间 RTT 就把发送方的 cwnd 增加 1 。

快重传、快恢复

主要作用就是快速恢复丢失的数据包。没有 FRR(快速重传和恢复) ,如果数据包丢失了,TCP 会使用定时器来要求传输暂停;有了 FRR ,如果接收方收到一个不按顺序的数据段,他会立刻给发送方发送一个重复确认,如果发送方连续收到三个重复确认,它会认为重复确认指出的数据段丢失了,并立即重传这些丢失的数据段,并且不会因为重传而要求传输暂停。

每当发生三次重复确认,就认为当前为本网络设置的拥塞避免门限值太大了,于是 ssthresh 就重新设定为当前窗口的一半,同时当前窗口大小也减半后,继续执行拥塞避免算法。

如果网络中发生发送方没有及时接收到 ACK 确认,也就是超时的情况,则认为在本网络中当前发送窗口过大了,于是 ssthresh 重新设定为当前窗口的一半,同时当前窗口大小降为 1 ,并执行慢开始算法。

在这里插入图片描述

图片出自谢希仁的《计算机网络》第七版

当有单独的数据包丢失时 FRR 能最有效地工作,如果短时间有很多数据包丢失 FRR 并不是很有效。(原因见上文连续 ARQ 协议)

附加题:浏览器输入一个URL之后显示主页的过程?

PS:这是一个经典面试题,甚至在学校的计网考试中最后一道简答题也是这个。。。
在这里插入图片描述

出自《图解HTTP》

  1. 先从本地缓存中查找 URL 对应的 IP 地址,如果本地缓存没有,会使用 DNS 协议,先从当地的根域名服务器查找对应的 IP 地址,如果没有则去对应的顶级 DNS 服务器查找,如果还没有则会去权威 DNS 服务器查找。

    一般具体的查询顺序是( 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,权威域名服务器缓存 )

  2. 三次握手建立 TCP 连接。(如果需要使用 HTTPS 协议,还需要进行 TLS 四次握手协商加密套件和会话秘钥用来实现之后的加密通信)

  3. 客户端通过已经建立的 TCP 连接,向服务器指定端口(HTTP 80/HTTPS 443)发送 HTTP 请求。

  4. 服务器接受处理客户端发来的 HTTP 请求,并返回 HTTP 响应报文。

  5. 客户端根据服务端响应来的各种数据,边解析边渲染构建 DOM 树、构建渲染树等等。。。并将其绘制到屏幕上。

  6. 关闭之前建立的连接。


最后再卑微的啰嗦一句:码字不易,如果有帮助到你请点赞关注+收藏哦!

本人菜鸟,有错误请告知,感激不尽!

更多题解源码和学习笔记:githubCSDNM1ng

猜你喜欢

转载自blog.csdn.net/qq_42758551/article/details/106342997