TCP为什么是可靠的

TCP的定义:是一种面向连接的、可靠的、基于字节流的传输层通信协议

那么肯定会有人疑惑,为什么他是可靠的呢?(也是在面试的过程中经常被问得)

数据可靠的本质就是当我向另一个人发送了一条短信,但是我不知道对方有没有收到这条短信,当我发现对方没有收到时,就要重新发送一条短信,知道对方确认收到为止。

TCP是怎样实现的呢?

  • TCP在传输的时候会有三次握手、以及四次挥手来建立连接和断开连接

  • 在数据传输时候,提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口、拥塞控制等方法

检验和

通过检验和的方式,接收端可以检测出来数据是否有差错和异常,假如有差错就会直接丢弃TCP段,重新发送。TCP在计算检验和时,会在TCP首部加上一个12字节的伪首部。检验和总共计算三部分:TCP首部、TCP数据、TCP伪首部。

序列号/确认应答

这个机制类似于问答的形式。比如在课堂上老师会问你“你明白了吗?”,假如你在一定时间内没有回应或者你回答不明白,那么老师就会重新讲一遍,其实计算机的确认应答机制也是一样的,发送端发送信息给接收端,接收端会回应一个包这个就是应答包

只要发送端有一个包传输,接收端没有回应确认包(ACK包),都会重发,也就是任何一方没有收到对方确认收到信息的信息,都会重发数据。这就保证了数据的完整性

超时重传

超时重传是指发送出去的数据包到接收到确认包之间的时间,如果超过了这个时间会被人认为是丢包了,需要重传,那么我们该如何确认这个时间值呢?

我们知道,一来一回的时间总是差不多的,都会有一个类似于平均值的概念。比如发送一个包到接收到收到这个包一共是0.5s,然后接收端回发一个确认包给发送也要0.5s,这样的两个时间就是RTT(往返时间)。可能由于网络原因的问题,时间会有偏差,称为抖动(方差)。

从上面的介绍来看,超时重传的时间大概是比往返时间+抖动值还要稍微大的时间

但是在重发的过程中,假如一个包经过多次的重发也没有收到对方的确认包,那么就会认为接收端异常,强制关闭连接,并且通知应用通信异常强行终止。

最大消息长度

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

滑动窗口控制

我们上面提到的超时重传的机制存在效率低下的问题,发送一个包到发送下一个包要经过一段时间才可以。所以我们就想着能不能不用等待确认包发送下一个数据包呢?这就提出了一个滑动窗口的概念

窗口的大小就是在无需等待确认包的情况下,发送端还能发送的最大数据量。这个机制的实现就是使用了大量的缓冲区,通过对多个段进行确认应答的功能。通过下一次的确认包可以判断接收端是否已经接收了数据,如果已经接收了就从缓冲区里面删除数据。

在窗口之外的数据就是还未发送的和对端已经收到的数据。那么发送端是怎样判断接收端有没有接收到数据呢?或者怎么知道需要重发的数据有哪些呢?或者怎么知道需要重发的数据有哪些呢?通过下面这个图就知道了

如上图,接收端在没有收到自己所期望的序列号数据之前,会对之前的数据继续进行重复确认。发送端在接收到某个应答包之后,又连续3次收到同样的应答包,则数据已经丢失,需要重发。

拥塞控制

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

此处引入一个拥塞窗口:

发送开始时定义拥塞窗口大小为1,;每次收到一个ACK应答,拥塞窗口加1;而在每次发送数据时,发送窗口取拥塞窗口与接送端接收窗口最小者

慢启动:在启动初期以指数增长方式增长;设置一个慢启动的阈值,当以指数增长达到阈值时就停止指数增长,按照线性增长方式增加至拥塞窗口;线性增长达到网络拥塞时立即把拥塞窗口设置回1,进行新一轮的“慢启动”,同时新一轮的阈值变为原来的一半。

TCP三次握手

TCP三次握手的目的就是建立可靠的通信,使确认双方都发送以及接收正常。

  • 开始前:客户端和服务端都处于close状态,服务端主动监听某个端口,处于LISTEN状态

  • 第一次握手:客户端发送SYN报文给服务端,客户端处于SYN-SENT 状态。此时服务端确认自己接收正常,客户端发送正常

  • 第二次握手:服务端收到客户端的SYN报文后,发送SYN+ACK报文给客户端,之后服务端处于SYN-RCD状态。此时客户端确认自己发送正常,接收正常,服务端发送正常,接收正常

  • 第三次握手:客户端收到服务端报文后,向服务端发送一个ACK报文。此时服务端确认自己发送正常,客户端接收正常。之后客户端处于ESTABLISHED 服务端收到客户端应答报文后,也进入ESTABLISHED 状态。

第三次握手是可以携带数据的,前两次握手是不可以携带数据的

一旦完成三次握手,双方都处于ESTABLISHED 状态,此时连接就已建立完成,客户端和服务端就可以相互发送数据了。

TCP四次挥手

确认双方都要断开连接,断开连接后主机中的资源被释放。

  • 第一次挥手:客户端打算断开连接,发送一个FIN报文(客户端:没什么要说的了吧,我要断开了)。客户端进入FIN_WAIT_1 状态,

  • 第二次挥手:服务端收到报文后,向客户端发送ACK报文,确认的序号为收到的序号加1(服务端:收到请求了)。服务端进入CLOSE_WAIT 状态,客户端进入FIN_WAIT_2 状态

  • 第三次挥手:服务端关闭客户端连接,向客户端发送一个FIN报文(服务端:我也没有什么要说的了,准备关闭)。服务端处于LAST_ACK 状态,客户端处于TIME_WAIT 状态。

  • 第四次挥手:客户端发送ACK报文,并将确认序号设置为收到序号加1(客户端:我知道了,我也关闭了)服务端收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

主动关闭连接的,才有TIME_WAIT状态

参考文章:

https://zhuanlan.zhihu.com/p/112317245

猜你喜欢

转载自blog.csdn.net/Rice_w/article/details/129261187