1226|1

1114

帖子

15

TA的资源

纯净的硅(高级)

楼主
 

计算机网络面试八股文总结:归纳核心知识点(3) [复制链接]

19.TCP 握手为什么是三次,为什么不能是两次?不能是四次?

为什么不能是两次?

防止已失效的连接请求报文段突然又传到服务端,因而产生错误

 

 

 

客户端发送出去的第一个连接请求报文段并没有丢失,而是因为某些未知原因在某个网络节点上发生滞留,导致延迟到连接释放以后的某个时间点才到达服务端。

本来这是一个早已失效的报文段,但是服务端收到此失效的报文段后,会误认为这是客户端再次发起的一个新的连接请求,于是服务端向客户端又发出确认报文,表示同意建立连接。

如果不采用 “三次握手”,那么只要服务端发出确认报文后就会认为新的连接已经建立了,但是客户端并没有发出建立连接的请求,因此不会向服务端发送数据,服务端没有收到数据就会一直等待,这样服务端就会白白浪费掉很多资源。

所以我们需要 “第三次握手” 来确认这个过程:

通过第三次握手的数据来告诉服务端,客户端有没有收到服务端 “第二次握手” 时传过去的数据,以及这个连接的序号是不是有效的。

若发送的这个数据是 “收到且没有问题” 的信息,服务端接收后就可以正常建立 TCP 连接,否则建立 TCP 连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求时发生的错误。

为什么不是四次?

简单来说,就是三次握手已经足够创建可靠的连接,没有必要再多一次握手导致花费更多的时间在建立连接上。

 

20.三次握手中每一次没收到报文会发生什么情况?

第一次握手服务端未收到 SYN 报文

服务端不会进行任何的动作,而客户端由于一段时间内没有收到服务端发来的确认报文,等待一段时间后会重新发送 SYN 报文,

如果仍然没有回应,会重复这个过程,直到发送次数超过最大重传次数,就会返回连接建立失败。

第二次握手客户端未收到服务端响应的 ACK 报文

因为第二次握手是包含对客户端第一次握手的 ACK 确认报文,所以如果客户端迟迟没有收到第二次握手,那么客户端就会觉得可能是自己的 SYN 报文(第一次握手)丢失了,于是客户端就会触发超时重传机制,重传 SYN 报文。

然后,因为第二次握手是包含服务端的 SYN 报文,所以当客户端收到后,需要给服务端发送 ACK 确认报文(第三次握手),服务端才会认为该 SYN 报文被客户端收到了。

那么,如果第二次握手丢失了,服务端就收不到第三次握手,于是服务端这边会触发超时重传机制,重传 SYN-ACK 报文。

第三次握手服务端未收到客户端发送过来的 ACK 报文

客户端收到服务端的 SYN-ACK 报文后,就会给服务端发送一个 ACK 报文,也就是第三次握手,此时客户端进入到 ESTABLISH(连接已建立) 状态。

因为这个第三次握手的 ACK 是对第二次握手的 SYN 的确认报文,所以当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手,或者达到最大重传次数。

 

21.第二次握手传回了 ACK,为什么还要传回 SYN?

ACK 是为了告诉客户端传来的数据已经接收无误。

而传回 SYN 是为了告诉客户端,服务端响应的确实是客户端发送的报文。

 

22.第三次握手可以携带数据吗?

第三次握手是可以携带数据的。

此时客户端已经处于连接已建立状态。对于客户端来说,它已经建立连接成功了,并且确认服务端的接收和发送能力是正常的。

第一次握手不能携带数据是出于安全的考虑,因为如果允许携带数据,攻击者每次在 SYN 报文中携带大量数据,就会导致服务端消耗更多的时间和空间去处理这些报文,会造成CPU和内存的消耗。

 

23.说说 TCP 四次挥手的过程?

 

 

 

  • 数据传输结束后,通信双方都可以主动发起断开连接请求,这里假定客户端发起。

  • 客户端发送释放连接报文,进行第一次挥手(FIN=1,ACK=1,seq=u,ack=v),发送完毕后,客户端进入 FIN_WAIT_1(终止等待1) 状态。

  • 服务端发送确认报文,进行第二次挥手(ACK=1,seq =v,ack=u+1),发送完毕后,服务端进入 CLOSE_WAIT(关闭等待) 状态,客户端收到这个确认包后,进入 FIN_WAIT_2(终止等待2) 状态。

  • 服务端发送释放连接报文,进行第三次挥手(FIN=1,ACK1,seq=w,ack=u+1),发送完毕后,服务端进入LAST_ACK(最后确认) 状态,等待来自客户端的最后一个 ACK 报文。

  • 客户端发送确认报文,进行第四次挥手(ACK=1,seq=u+1,ack=w+1),客户端收到来自服务端的关闭请求,发送一个确认包,并进入 TIME_WAIT(时间等待) 状态,服务端接收到这个确认包后,关闭连接,进入 CLOSED(关闭) 状态。

  • 客户端再经过 2MSL 后,也进入 CLOSED(关闭) 状态。

客户端在发送完最后一个确认报文后,为什么不直接进入关闭状态 ? 而是要进入时间等待状态,2MSL 后才进入关闭状态,这是否有必要呢 ?

 

 

服务端发送TCP连接释放报文段后进入最后确认状态。

客户端收到该报文段后,发送普通的TCP确认报文段,并进入关闭状态而不是时间等待状态。然而,该TCP确认报文段丢失了。

这必然会造成服务端对之前所发送的TCP连接释放报文段的超时重传,并仍处于最后确认状态。重传的TCP连接释放报文段到达客户端,由于客户端处于关闭状态,因此不理睬该报文段,这必然会造成服务端反复重传TCP连接释放报文段,并一直处于最后确认状态而无法进入关闭状态。

因此时间等待状态以及处于该状态2MSL时长,可以确保服务端可以收到最后一个TCP确认报文段而进入关闭状态。

另外,客户端在发送完最后一个TCP确认报文段后,再经过2MSL时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的TCP连接中,不会出现旧连接中的报文段。

为什么等待时间是2MSL?

MSL 是报⽂最⼤⽣存时间,它是任何报⽂在⽹络上存在的最⻓时间,超过这个时间报⽂将被丢弃。

TIME_WAIT 等待 2 倍的 MSL,是因为⽹络中可能存在来⾃发送⽅的数据包,当这些发送⽅的数据包被接收⽅处理后⼜会向对⽅发送响应,所以⼀来⼀回需要等待 2 倍的时间。

⽐如服务端如果没有收到客户端发送的TCP确认报文段,就会触发超时重传,重新发送TCP连接释放报文段,客户端收到后,会重发TCP确认报文段给服务端, ⼀来⼀去正好 2 个 MSL。

 

24.TCP 挥手为什么需要四次呢?

再来回顾下四次挥手双方发 FIN 包的过程,就能理解为什么需要四次了。

关闭连接时,客户端向服务端发送 FIN 报文,仅仅表示客户端不再发送数据了但是还能接收数据。

服务端收到客户端的 FIN 报文后,先返回一个 ACK 确认报文;而服务端可能还有数据需要处理和发送,等服务端不再发送数据了,再发送 FIN 报文给客户端来表示同意现在关闭连接。

从上面的过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而导致比三次握手多了一次。

 

25.TCP 保活计时器有什么用?

除了时间等待计时器外,TCP 还有一个保活计时器(keepalive timer)。

设想这样的场景:

TCP 双方已经建立了连接,后来,客户端的主机突然出现了故障。显然,服务端以后就不能再收到客户端发来的数据。因此,应当有措施使服务端不要再白白等待下去。这就需要使用保活计时器了。

服务端每收到一次客户端的数据,就重新设置并启动保活计时器(2小时定时)。若定时周期内都没有收到客户端发来的数据,服务端就发送一个探测报文段,以后每隔 75 秒钟发送一次。若连续发送 10 个探测报文段后仍然无客户端的响应,服务端就认为客户端出了故障,接着就关闭这个连接。

 

26.CLOSE-WAIT 的状态和意义?

服务端收到客户端关闭连接的请求并确认之后,就会进入 CLOSE-WAIT 状态。

此时服务端可能还有一些数据没有传输完成,因此不能立即关闭连接,而 CLOSE-WAIT 状态就是为了保证服务端在关闭连接之前将待发送的数据处理完。

 

27.说说 TCP 报文首部有哪些字段?

 

 

 

16位端口号:源端口号,标识发送该 TCP 报文段的应用进程;目的端口号,标识接收该 TCP 报文段的应用进程。

32位序号:指出本 TCP 报文段数据载荷的第一个字节的序号。32位序号:指出本 TCP 报文段数据载荷的第一个字节的序号。

32位确认号:指出期望收到对方下一个 TCP 报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有数据的确认。若确认号 = n,则表明到序号 n-1 为止的所有数据都已正确接收,期望收到序号为 n 的数据。

4位头部长度:指出 TCP 报文段的首部长度。

6位标志位:

  • 确认标志位ACK:取值为1时确认号字段才有效,取值为0时确认号字段无效。TCP 规定,在连接建立后所有传送的 TCP 报文段都必须把 ACK 置为1。

  • 同步标志位SYN:在 TCP 连接建立时用来同步序号。

  • 终止标志位FIN:用来释放 TCP 连接。

16位窗口大小:

  • 指出发送本报文段的一方的接收窗口。

  • 窗口值作为接收方让发送方设置其发送窗口的依据。

  • 这是以接收方的接收能力来控制发送方的发送能力,称为流量控制。

  • 发送窗口的大小还取决于拥塞窗口的大小,也就是应该从接收窗口和拥塞窗口中取小者。

16位校验和:用来检查整个 TCP 报文段在传输过程中是否出现了误码。

16位紧急指针:当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个 TCP 报文段中进行发送。紧急指针会指出本报文段的数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。

 

28.TCP 是如何保证可靠性的?

TCP主要提供了 连接管理、校验和、序列号/确认应答、流量控制、最大消息长度、超时重传、拥塞控制等方式实现了可靠传输。

连接管理:TCP 使用三次握手和四次挥手来保证可靠地建立连接和释放连接。

校验和:用来检查整个 TCP 报文段在传输过程中是否出现了误码。

序列号/确认应答:TCP 会给发送的每一个包进行编号,接收方会对收到的包进行应答,发送方就会知道接收方是否收到对应的包,如果发现没有收到,就会重发,这样就能保证数据的完整性了。

流量控制:TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据大小。当接收方来不及处理发送方的数据时,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。(TCP 利用滑动窗口实现流量控制)

最大消息长度:在建立 TCP 连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行重传的。理想情况下是该长度的数据刚好不被网络层分块。

超时重传:超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间,就会被认为是丢包了,需要重传。

拥塞控制:如果网络非常拥堵,此时再发送数据就会加重网络负担,那么发送的数据段很可能超过了最大生存时间也没有到达接收方,就会产生丢包问题。为此 TCP 引入了慢启动机制,先发出少量数据,就像探路一样,先摸清当前的网络拥堵状态后,再决定按照多大的速度传送数据。

 

29.说说 TCP 的流量控制?

TCP 提供了一种机制,可以让发送方根据接收方的实际接收能力控制发送的数据量,这就是流量控制。

TCP 通过「滑动窗口」来实现流量控制

首先 TCP 双方进行三次握手,初始化各自的窗口大小,均为 400 字节。

 

 

 

假如当前发送方给接收方发送了 200 字节,那么,发送方的SND.NXT会右移 200 字节,也就是说当前的可用窗口减少了 200 字节。

接收方收到后,放到缓冲队列里面,REV.WND = 400-200=200 字节,所以 win=200 字节返回给发送方。接收方会在 ACK 的报文首部带上缩小后的滑动窗口 200 字节

发送方又发送 200 字节过来,200 字节到达,继续放到缓冲队列里面。不过这时候,由于大量负载的原因,接收方处理不了这么多字节,只能处理 100 字节,剩余的 100 字节继续放到缓冲队列里面。这时候,REV.WND = 400-200-100=100 字节,即 win=100 字节返回给发送方。

发送方继续发送 100 字节过来,这时候,接收窗口 win 变为 0。

发送方停止发送,开启一个定时任务,每隔一段时间,就去询问接收方,直到 win 大于 0,才开始继续发送。

 

30.详细说说 TCP 的滑动窗口?

TCP 发送一个数据,如果需要收到确认应答才会发送下一个数据。这样的话就会有个缺点:效率会比较低。

为了解决这个问题,TCP 引入了滑动窗口,它是操作系统开辟的一个缓存空间。窗口大小表示无需等待确认应答而可以继续发送数据的最大值。

TCP 头部有个 16 位的窗口大小,它告诉对方本端的 TCP 接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到流量控制的目的。

通俗点讲,就是接收方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的接收缓冲区还有多少空闲空间,缓冲区的空闲空间,我们就称之为接收窗口大小。

TCP 滑动窗口分为两种: 发送窗口和接收窗口。

发送方的滑动窗口包含四个部分:

  1. 已发送且已收到 ACK 确认

  2. 已发送但未收到 ACK 确认

  3. 未发送但可以发送

  4. 未发送且不可发送

 

 

 

  • 虚线矩形框,就是发送窗口。

  • SND.WND:表示发送窗口的大小,上图虚线框的格子数是 14 个,即发送窗口大小是 14。

  • SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。

  • SND.UNA:一个绝对指针,它指向的是已发送但未收到确认的第一个字节的序列号。

接收方的滑动窗口包含三个部分:

  1. 已成功接收并确认

  2. 未收到数据但可以接收

  3. 未收到数据且不可以接收的数据

 

 

 

  • 虚线矩形框,就是接收窗口。

  • REV.WND:表示接收窗口的大小,上图虚线框的格子数就是 9 个,即接收窗口的大小是 9。

  • REV.NXT:下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。

 

31.说说 TCP 的拥塞控制?

什么是拥塞控制?不是有了流量控制吗?

前⾯的流量控制是避免发送⽅的数据填满接收⽅的缓存,但是并不知道整个⽹络中发⽣了什么。

⼀般来说,计算机⽹络都处在⼀个共享的环境。因此也有可能会因为其他主机之间的通信使得⽹络出现拥堵。

在⽹络出现拥堵时,如果继续发送⼤量数据包,可能会导致数据包延迟、丢失等,这时 TCP 就会重传数据,但是⼀重传就会导致⽹络的负担更重,于是会导致更⼤的延迟以及更多的丢包,这个情况就会进⼊恶性循环并且被不断地放⼤…

所以,TCP 不能忽略整个网络中发⽣的事,它被设计成⼀个⽆私的协议,当⽹络发送拥塞时,TCP 会⾃我牺牲,降低发送的数据流。

于是,就有了拥塞控制,拥塞控制的⽬的就是为了避免发送⽅的数据填满整个⽹络。

就像是一个水管,不能让太多的水(数据流)流入水管,如果超过水管的承受能力,水管就会被撑爆(丢包)。

发送方维护一个拥塞窗口 cwnd(congestion window) 的变量,调节所要发送数据的量。

什么是拥塞窗⼝?和发送窗⼝有什么关系呢?

拥塞窗⼝ **cwnd **是发送⽅维护的⼀个状态变量,它会根据⽹络的拥塞程度动态变化。

发送窗⼝ swnd 和接收窗⼝ rwnd 是约等于的关系,那么由于加⼊了拥塞窗⼝的概念后,此时发送窗⼝的值 swnd = min(cwnd, rwnd),也就是取拥塞窗⼝和接收窗⼝中的最⼩值。

拥塞窗⼝ cwnd 变化的规则:

  • 只要⽹络中没有出现拥塞, cwnd 就会增⼤

  • 但如果⽹络中出现了拥塞, cwnd 就会减小

拥塞控制有哪些常用算法?

慢启动

慢启动算法,慢慢启动。

它表示 TCP 建立连接完成后,一开始不要发送大量的数据,而是先探测一下网络的拥塞程度。由小到大逐渐增加拥塞窗口的大小,如果没有出现丢包,每收到一个 ACK,就将拥塞窗口 cwnd 的大小加 1(单位是 MSS)。每轮次发送窗口增加一倍,呈指数增长,如果出现丢包,拥塞窗口就减半,进入拥塞避免阶段。

举个例子:

  • 连接建⽴完成后,⼀开始初始化 cwnd = 1 ,表示可以传⼀个 MSS ⼤⼩的数据。

  • 当收到⼀个 ACK 确认应答后,cwnd 增加 1,于是⼀次性能够发送 2 个。

  • 当收到 2 个 ACK 确认应答后, cwnd 增加 2,于是就能⽐之前多发送 2 个,所以这⼀次能够发送 4 个。

  • 当这 4 个 ACK 确认到来的时候,每个确认 cwnd 增加 1, 4 个确认 cwnd 增加 4,于是就能⽐之前多发送 4 个,所以这⼀次能够发送 8 个。

 

 

 

发送包的个数是呈指数性增⻓的。

 

 

 

为了防止 cwnd 增长过大而引起网络拥塞,还需设置一个慢启动阀值 ssthresh(slow start threshold)的状态变量。当 cwnd 到达该阀值后,就好像水管被关小了水龙头一样,减少了拥塞状态。即当 cwnd > ssthresh 时,进入拥塞避免算法。

拥塞避免

一般来说,慢启动阀值 ssthresh 的大小是 65535 字节,cwnd 到达慢启动阀值后

  • 每收到一个 ACK 时,cwnd = cwnd + 1/cwnd

  • 当每过一个 RTT 时,cwnd = cwnd + 1

显然这是一个线性上升的算法,可以避免发送过快导致网络出现拥塞问题。

接着上面慢启动的例子,假定 ssthresh 为 8:

  • 当 8 个 ACK 确认应答到来时,每个确认增加 1/8,8 个 ACK 确认后 cwnd ⼀共增加 1,于是这⼀次能够发送 9 个 MSS ⼤⼩的数据,变成了线性增⻓。

 

 

 

拥塞发生

当网络拥塞发生丢包时,会有两种情况:

  • RTO 超时重传

  • 快速重传

如果是发生了RTO 超时重传,就会使用「拥塞发生」算法

  • 慢启动阀值 sshthresh = cwnd/2

  • cwnd 重置为 1

  • 进入新的慢启动过程

 

 

 

这真的是辛辛苦苦几十年,一朝回到解放前。其实还有更好的处理方式,就是「快速重传」。当发送方收到 3 个连续的重复 ACK 时,就会快速地重传,不必等待RTO超时再重传。

 

 

 

发⽣「快速重传」的拥塞发⽣算法:

  • 拥塞窗口大小 cwnd = cwnd/2

  • 慢启动阀值 ssthresh = cwnd

  • 进入快速恢复算法

快速恢复

快速重传和快速恢复算法一般是同时使用的。快速恢复算法认为,还能收到 3 个重复的 ACK,说明网络也没有那么糟糕,所以没必要像 RTO超时重传 那样强烈。

正如前面所说的,进入快速恢复之前,cwnd 和 sshthresh 已被更新:

  • cwnd = cwnd/2

  • sshthresh = cwnd

然后,真正进入「快速恢复」算法:

  • cwnd = sshthresh + 3

  • 重传重复的那几个 ACK(即丢失的那几个数据包)

  • 如果再收到重复的 ACK,那么 cwnd = cwnd +1

  • 如果收到新数据的 ACK 后,cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入「拥塞避免」算法了。

 

 

 

32.说说 TCP 的重传机制?

重传包括:超时重传、快速重传、带选择确认的重传(SACK)、重复 SACK 四种。

超时重传

超时重传,是 TCP 协议保证数据可靠性的另一个重要机制,其原理是在发送某一个数据以后就开启一个重传计时器,在一定时间内如果没有收到发送的数据报的 ACK 报文,那么就重新发送数据,直到收到 ACK 报文为止。

超时时间应该设置为多少合适呢?

 

 

 

RTT 就是数据完全发送完,到收到确认信号的时间,即数据包的一次往返时间。

超时重传时间,就是 RTO(Retransmission Timeout)。那么,RTO 应该设置多大呢?

  • 如果 RTO 设置很大,等了很久都没重发,这样肯定不行。

  • 如果 RTO 设置很小,那很可能数据都没有丢失,就开始重发了,这将会导致网络阻塞,从而发生恶性循环,导致更多的超时出现。

一般来说,RTO 略微大于 RTT,效果是最佳的。

超时重传并不是十分完美的重传方案,它有这些缺点:

  • 当一个报文丢失时,会等待一定的超时周期,才重传分组,增加了端到端的时延。

  • 当一个报文丢失时,在其等待超时的过程中,可能会出现这种情况:其后面的报文段已经被接收方接收了但却迟迟得不到确认,发送方会认为其后面的报文段也丢失了,从而引起不必要的重传,既浪费资源也浪费时间。

快速重传

快速重传可以用来解决超时重发的时间等待问题。

它不以时间驱动,而是以数据驱动。它是基于接收方的反馈信息来引发重传的。

快速重传的流程如下:

 

 

 

发送方发送了 1,2,3,4,5,6 份数据:

  • 第一份 Seq=1 先送到了,于是 ACK 回2;

  • 第二份 Seq=2 也送到了,于是 ACK 回3;

  • 第三份 Seq=3 由于网络等某些原因,没送到;

  • 第四份 Seq=4 送到了,但是由于 Seq=3 没收到。因此 ACK 还是回3;

  • 后面的 Seq=5,6 也送到了,ACK 还是回复3,因为 Seq=3 没有收到。

  • 发送方连续收到三个重复冗余的 ACK=3 的确认(其实是4个哈,但是因为前面的一个是正常的ACK,后面三个才是重复冗余的),于是知道哪个报文段在传输过程中丢失了;发送方就在重传定时器过期之前,重传该报文段。

  • 最后,接收方收到了 Seq=3,此时因为 Seq=4,5,6 都收到了,于是它回 ACK=7。

快速重传机制也有缺点:发送方并不知道到底是哪个报文丢失了,到底该重传多少个数据包?

是只重传 Seq=3 ?还是重传 Seq=3、Seq=4、Seq=5、Seq=6 呢?因为发送方并不清楚这三个连续的 ACK=3 是谁传回来的。

带选择确认的重传(SACK)

为了解决应该重传多少个包的问题? TCP 提供了带选择确认的重传(即 SACK,Selective Acknowledgment)。

SACK 机制就是,在快速重传的基础上,接收方返回最近收到报文段的序列号范围,这样发送方就知道接收方哪些数据包是没收到的。这样就很清楚应该重传哪些数据包。

 

 

 

如上图中,发送⽅收到了三次同样的 ACK 确认报⽂,于是就会触发「快速重传」机制,通过 SACK 信息发现只有 200~299 这段数据丢失,则重发时,就只选择了这个 TCP 段进⾏重发。

重复 SACK(D-SACK)

D-SACK,英文是 Duplicate SACK,是在 SACK 的基础上做了一些扩展,主要用来告诉发送方,有哪些数据包,自己重复接受了。

D-SACK 的目的是帮助发送方判断,是否发生了包失序、ACK 丢失、包重复或伪重传。让 TCP 可以更好的做网络流控。

例如 ACK 丢包导致的数据包重复:

 

 

 

  • 接收⽅发给发送⽅的两个 ACK 确认应答都丢失了,所以发送⽅超时后,重传第⼀个数据包(3000 ~ 3499)

  • 接收⽅发现数据是重复收到的,于是回了⼀个 SACK = 3000~3500,告诉「发送⽅」 3000~3500的数据早已被接收了,因为 ACK 都到 4000 了,意味着 4000 之前的所有数据都已经收到了,所以这个 SACK 就代表着 D-SACK 。这样发送⽅就知道了,数据并没有丢,而是接收⽅的 ACK 确认报⽂丢了。

 

33.说说 TCP 的粘包和拆包?

什么是 TCP 粘包和拆包?

TCP 是面向字节流,没有界限的一串数据。TCP 底层并不了解上层业务数据的具体含义,它会根据 TCP 缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被 TCP 拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包进行发送,这就是所谓的 TCP 粘包和拆包问题。

 

 

 

为什么会产生粘包和拆包呢?

  • 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次性发送出去,将会发生粘包;

  • 接收方的应用层没有及时读取接收缓冲区的数据,将会发生粘包;

  • 要发送的数据大于 TCP 发送缓冲区剩余空间的大小,将会发生拆包;

  • 待发送的数据大于 MSS(最大报文长度),TCP 在传输前将会进行拆包。即 TCP报文长度 - TCP头部长度 > MSS。

解决方案:

  • 发送方给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收方在收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

  • 发送方将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收方每次从接收缓冲区中读取固定长度的数据,就自然而然的把每个数据包拆分开来。

  • 可以在数据包之间设置边界,如添加特殊符号,这样接收方通过这个边界就可以将不同的数据包拆分开来。

此帖出自RF/无线论坛

最新回复

你把其他地方的文章的抄过来不好吧   详情 回复 发表于 2023-10-1 20:11
点赞 关注
 

回复
举报

2721

帖子

0

TA的资源

纯净的硅(中级)

沙发
 

你把其他地方的文章的抄过来不好吧

此帖出自RF/无线论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表