- 数据传输结束后,通信双方都可以主动发起断开连接请求,这里假定客户端发起。
- 客户端发送释放连接报文,进行第一次挥手(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 滑动窗口分为两种: 发送窗口和接收窗口。
发送方的滑动窗口包含四个部分:
- 已发送且已收到 ACK 确认
- 已发送但未收到 ACK 确认
- 未发送但可以发送
- 未发送且不可发送