2 面试题之TCP/UDP

筅森魡賤 提交于 2020-08-17 10:47:49

大纲:

 

① TCP和UDP协议的区别?(重点掌握)

答:TCP和UDP协议都是传输层常见的协议,它们的主要区别如下所示:

  • TCP协议进行数据通信之前需要三次握手建立连接,UDP协议不需要建立连接即可发送数据。
  • TCP有确认机制,丢包可以重发,保证数据的正确性;UDP不保证正确性,只是单纯的负责发送数据包。
  • TCP协议可能会对大数据包进行拆分,并且在接收方进行重组数据包操作;UDP协议是面向报文的,不会进行分片和重组,所以需要注意传输的报文大小。
  • 网络包中的TCP头部为20个字节;UDP头部只有8个字节。

 

解析:

这也是一道几乎必考的面试题目,我们必须清楚的阐述是否需要三次握手以及传输是否可靠,即是否有确认机制

既然说到了丢包重传机制,那么请注意SACK (Selective ACK),SACK是TCP选项,它使得接收方能告诉发送方哪些报文段丢失,哪些报文段重传了,哪些报文段已经提前收到等信息,根据这些信息TCP就可以只重传哪些真正丢失的报文段。

 

UDP协议的应用:

UDP协议由于传输不需要建立连接,资源消耗较小。常用在视频或者语音传输中,域名解析服务DNS都使用了UDP协议。

 

 

② 可以详细说一下三次握手以及四次挥手吗?(重点掌握)

参考视频链接:https://www.bilibili.com/video/BV1h7411A7tG

答:TCP协议是一种可靠的协议,在正式传输数据之前必须通过三次握手建立连接并且互相交换窗口大小。在传输结束之后,通过四次挥手来确认双方都结束数据交互。

TCP共有6个标志位,分别是:(这个用于下面过程中概念的理解)

  • SYN(synchronous),建立联机。
  • ACK(acknowledgement),确认。
  • PSH(push),传输。
  • FIN(finish),结束。
  • RST(reset),重置。
  • URG(urgent),紧急。

三次握手的状态流程图如下所示:

客户端经历了Close->SYN_SENT->ESTABLISHED的状态变化;
服务端经历了Close->Listen->SYN_RCVD->EATABLISHED的状态变化。

详细过程:

  • 第一次握手:客户端要和服务端通信, 首先要告知服务端一声,发送一个 SYN=1的连接请求信号;(SYN)
  • 第二次握手: 当服务端接收到客户端的连接请求,此时要给客户端回复一个ACK的确认信息,说明我这边已经准备好了;同时发送一个SYN的连接请求信号;(SYN + ACK)
  • 第三次握手: 当客户端收到了服务端的确认连接信息后,要回复一个ACK的确认信号,说明可以开始通信;(ACK)

举个栗子:

----------------------------------------------------------------------------------------------

四次挥手的状态流程图如下所示:

客户端经历的状态变化为:
    ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSE
服务端经历的状态变化为:
    ESTABLISHED->CLOSE_WAIT-> LAST_ACK->CLOSE

详细过程:

  • 第一次挥手:双方通讯要结束时,客户端给服务端发送一个FIN信号,表示信息发送完毕, 此时自身形成等待结束连接的状态
  • 第二次挥手:服务端收到客户端的信号后,回复一个ACK确认信号,表明我知道你信息发完了;
  • 第三次挥手:此时客户端处于等待结束的状态,服务端信息也发送完毕,处于等待关闭连接的状态。客户端给服务端发送一个FIN信号,说明信息发送完毕,需要关闭连接;
  • 第四次挥手:客户端收到服务端的信息后,回复ACK表明收到信息。客户端为自己定义了一个定时器, 因为不知道刚才说的这句话能不能准确到达服务端(网络不稳定或者其他因素引起的网络原因),默认时间定为两个通信的最大时间之和,超出这个时间就默认服务器端已经接收到了自己的确认信息,此时客户端就关闭自身连接,服务器端一旦接收到客户端发来的确定通知就立刻关闭服务器端的连接。

举个栗子:(感觉这图有问题)

--------------------------------------------------------------------------------------------

面试官:“为什么需要三次握手?两次可以吗?“

答:不可以(非常坚定的语气)。可以给面试官举个例子:假如只有前面2次握手,那么服务端来收到SYN并且发出SYN+ACK包之后就会处于工作状态。如果服务端在某一时刻突然收到了一个来自客户端的SYN包,在发出ACK之后,服务端处于工作状态。但是可能这个包是卡了很久已经被客户端给丢弃了。客户端收到SYN+ACK之后,表示情绪淡定不予理会,但是服务端已经处于工作状态了,会造成资源的浪费。
图示:

参考视频链接:https://www.bilibili.com/video/BV1aJ41157kL?from=search&seid=4354844723518789082

 

面试官:“为什么断开连接需要四次?“

答:根据状态流程图,我们可以看出服务端响应断开连接的请求时,其ACK和FIN包并不是一起发送给客户端的,因为第一次由客户端->服务端的FIN信号表示的是客户端想要断开连接。服务端先给出ACK确认信号,表示已经收到FIN请求,然后当自己也可以结束的时候,再次发送FIN信号,所以需要挥手交互需要四次。

 

面试官:“四次挥手主动方为什么需要等待2MSL (两个通信报文的最大时间) ?“

答:当客户端最终告诉服务器端断开确认的时候,他不知道自己的发出的指令是否能准确的一次性被服务器接收。假如服务器没有接收到(这已经耗费了一个报文的最大通信时间了),服务器端将会重新发起一个结束通话的指令(FIN)到客户端,客户端又接收到了服务器发来的结束通信指令将继续给服务器进行一个确认,有人会说那要是客户端发出的确认信息服务端没收到,而服务端重发的断开指令客户端也没收到怎么办,说实话我也无奈,遇到这种情况咱们干脆认为网确实不行了。

上述问题以及过程可参考链接: https://blog.csdn.net/du5006150054/article/details/80157447

--------------------------------------------------------------------------------------------

注意:

我们在本知识点中所说的客户端和服务端其实都是相对的概念,也可以叫做主动方和被动方。介绍三次握手的时候,我们说到了双方会交换窗口大小,那么什么是窗口呢?

滑动窗口:

位于传输层的TCP协议是面向连接的,可靠的传输协议,拥有着确认机制。理论上,每发一个数据包都会收到其对应的确认包,然后才可以继续发送数据。

在三次握手阶段,双方互相将自己的最大可接收的数据量告诉对方,也就是自己的数据接收缓冲池的大小。这样对方可以根据已发送的数据量来计算是否可以接着发送。在处理过程中,当接收缓冲池的大小发生变化时,要给对方发送更新窗口大小的通知,利用滑动窗口机制有效提高通信效率。

 

 

③ TCP的拥塞避免算法有哪些?

关于拥塞,要注意2个方向的问题:1 如何知晓产生了拥塞?;2避免拥塞的算法;

参考链接:https://blog.csdn.net/hanzhen7541/article/details/79073549

此处暂时重点只说明一下避免拥塞的算法。

-------------------------------------------------------------------------------------------------------------

当网络中的资源供应不足,网络中的资源无法满足实际的资源需求时,网络的性能就会变差,因为传输数据需要资源。简单来说就是吃饭的人太多了,做饭的人人手不够,满足不了吃饭的人的需求(吃不饱)。

拥塞控制:就是对输入网络的数据进行限制, 防止过多的数据注入到网络中 ,使得网络中的路由器或链路不致过载 。(食堂做不了那么多饭,就对进入食堂的人进行限制,只让女生进食堂,男生不能进)

拥塞避免算法主要有如下两种:

  • 慢启动+拥塞避免
  • 快重传+快恢复

 

方式一:慢启动+拥塞避免

参考链接:https://blog.csdn.net/Regemc/article/details/80808469

参考链接:https://mp.weixin.qq.com/s?__biz=Mzg2NzA4MTkxNQ==&mid=2247485204&idx=1&sn=27daef390eec05b3d5db7cebcdcb4b7c&source=41#wechat_redirect

首先说明TCP维护的两个变量:

cwmd(拥塞窗口): 它表示发送方一次想要发送多少个字节的数据 ;

ssthresh (慢启动门限): 这是一个阈值,当 cwnd 超过这个值的时候,慢启动算法结束,进入拥塞避免算法

 

慢启动过程

  • 一开始发送数据时,因为不知道网络的状况,一下子把大量数据扔到网络中可能会造成网络瘫痪。所以刚开始先对网络进行探测一下,发送cwmd=1的报文,当收到了该报文的确认后,就把cwmd加1,此时cwmd=2;
  • 然后再发送cwmd=2的报文(2个报文)到网络,发送方每收到一个报文,cwmd就加1,这里结束后cwmd=4。
  • 然后发送方再发送cwmd=4的报文(4个报文)到网络,同样是每接受一个确认,cwmd就加1。重复执行这个过程,过程图示如下:

如果cwmd像这样持续增长,网络迟早要拥塞,所以要给cwmd设置一个上限,不能无休止的增长。这里引出慢启动门限ssthresh , 这是一个阈值,当 cwnd 超过这个值的时候,慢启动算法结束,进入拥塞避免算法

ssthresh 变量在一开始也是有默认值的,比如 ssthresh = 16. 接下来,我们讨论 cwnd > ssthresh 后,TCP 的行为;

 

拥塞避免算法

  • 当 cwnd > ssthresh 时,转而执行拥塞避免算法 。 这时候,TCP 发送 cwnd 个报文后,如果接收到了确认,cwnd 的值只是加 1,而不是加倍;这样,拥塞窗口 cwnd 就会按线性规律缓慢增长; (cwmd增加设置:每次只增加1)
  • 无论是在慢启动阶段,还是在拥塞避免阶段,只要发送方判断网络出现拥塞(依据就是没有按照收到确认),就要把 ssthresh 设置为出现拥塞时的 cwnd 值的一半(注意这只是一种策略,实际实现中不一定是这样的,RFC 中给出的公式是将已发出但是还未被确认的数据字节数来设置 ssthresh 的值);( ssthresh设置:减半)
  • 在更新了 ssthresh 后,同时将 cwnd 重新设置为 1,又开始执行慢启动算法。这样做的目的是要迅速减少主机发送到网络中的分组数,使得发生拥塞的中间设备有足够的时间把缓冲区中积压的分组处理完毕。

 

两个阶段的整体图示如下:

注意到图中的两个术语:“加法增大(Additive Increase)”和“乘法减小(Multiplicative Decrease)”。

加法增大是指执行拥塞避免算法后,使拥塞窗口 cwnd 缓慢增大,以防止网络过早出现拥塞;而乘法减小,是指不论在慢开始阶段还是在拥塞避免阶段,只要出现超时(即很可能出现了网络拥塞),就把 ssthresh 减半,即 ssthresh = cwnd/2,紧接着,cwnd = 1.
 

方式二:快重传+快恢复

快重传

1  快重传算法首先要求接收方每收到一个失序的报文(就是不是连续的报文,出现有序号缺失的报文)段就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方),然后若是发送方接收到3个重复确认ACK,则启动快重传算法。 (重复确认失序报文)

2 快重传算法还规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必继续等待M3设置的重传计时器RTO到期。(立即重传丢失报文)

具体说明:   接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4、M5、M6。显然,接收方不能确认M4、M5、M6,因为M4、M5、M6是收到的失序报文段。按照快重传算法的规定,接收方应及时发送对M2的重复确认,这样,发送方共收到了接收方的四个对M2的确认,其中后三个都是重复确认。 过程图示如下:

 

快恢复

快恢复与快重传配合使用,大致分为2个过程:

  • 阶段一:当在快重传阶段,发送方收到3个连续的重复确认,就把ssthresh (慢启动门限)减半,防止网络发生拥塞。注意,接下来不执行慢启动
  • 阶段二:发送方认为网络可能没有发生拥塞,所以就不执行慢开始算法(即:cwnd不设置成1;此处与慢启动不同),而是把cwnd值设置为慢开始门限ssthresh减半后的数值,然后使 拥塞窗口缓慢地线性增大。 图示如下:

 

 

④ TCP流量控制(滑动窗口)

1 知识背景

双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来,这时候接收方只能把处理不过来的数据存在缓存区里(失序的数据包也会被存放在缓存区里)。

如果缓存区满了发送方还在疯狂着发送数据,接收方只能把收到的数据包丢掉,大量的丢包会极大着浪费网络资源,因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。

对发送方发送速率的控制,我们称之为流量控制

 

2 如何进行流量控制?

  • 接收方在收到数据包后,在发送确认报文时,可以告诉发送方自己的缓存区还有多少剩余空间,我们将缓存区的剩余空间大小称为接收窗口大小,用变量win来表示接收窗口的大小
  • 发送方收到接收方的窗口大小后,会自行调节自己的发送速率, 当发送方收到接收窗口的大小为0时,发送方就会停止发送数据 ;

 

3 发送方何时再次发送数据?

当发送方停止发送数据后,该怎样才能知道自己可以继续发送数据?

方案一:当接收方处理完数据,win>0时,我们可以让接收方给发送方发信息,高速发送方可以继续发信息了;

这种方案的问题在于,如果接收方给发送方发送的报文丢失了,发送方没有得到继续发送数据的信息,这样发送方和接收方就会陷入互相等待的僵局,所以这种方法方案不合适。

方案二:当发送方收到接收窗口win=0时,停止发送数据,同时启动一个定时器,每过一段时间就会给接收端发送询问报文,确认是否可以发送数据?如果可以,接收方就会告诉发送方窗口大小;如果不可以,返回的win仍然是0,此时发送方将定时器重置,继续等待。

 

参考链接:https://www.cnblogs.com/kubidemanong/p/9987810.html

 

 

 

 

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!