TCP是一个面向字节流,可靠,全双工,有连接的协议.

那么TCP为什么是一个可靠的协议呢?

        TCP是一个可靠的协议是由于它的十个核心机制:分别是

                 1.确认应答

                 2.超时重传

                 3.建立连接

                 4.滑动窗口

                 5.流量控制

                 6.拥塞控制

                 7.延时应答

                 8.捎带应答

                 9.面向字节流

                 10.异常处理

        TCP可靠主要是用的前三个机制,确认应答,超时重传和建立连接.

                 确认应答这个机制就是发送方发送一条数据给接收方,接收方会返回一个ACK应答报文给发送方说明我收到了.超时重传就是发送方发送一条数据之后,达到一定的时间还没有收到接收方返回的ACK报文,那么发送方就会再次发送数据.这样进行一问一答的操作确保了TCP是一个可靠的协议.但是这样的效率比起UDP来就会低很多.

                 TCP建立连接这个机制是通过三次握手建立连接,断开连接是通过四次挥手断开连接.

那么三次握手具体是怎么做的呢?

                         三次握手的过程类似于投石问路,先测试一下网络通信的线路是否正常.发送方在第一次握手的时候会发送SYN报文告诉接收方我要和你建立连接了.这个时候接收方就会返回一个SYN报文和ACK报文告诉发送方,我收到了,我也要和你建立连接了.发送方收到之后也会给接收方发送一个ACK报文说明它也收到了.接收方发送的ACK和SYN报文是一起发送的,所以是三次握手.如下图所示: (图比较简略)

那么为什么是三次握手不是两次或者四次呢?

                 可以类比打游戏连麦。游戏开始之前,A和B肯定会先测试一下耳机和麦克风有没有问题:A喂一声,B随后喂两声,A听到之后再喂三声,这样A和B都可以确认对方的耳机和麦克风没有问题。如果只是两次,B喂了之后A没有回应,B就会认为自己的麦克风有问题,所以不能是两次握手。四次握手又太多余了,能确认的都确认完了,再加就只是重复。

四次挥手:TCP断开连接的时候会进行四次挥手。发送方会发送一个FIN报文给接收方,接收方收到之后先返回一个ACK,表示我收到了;等接收方把剩下的数据处理完,再发送一个FIN,表示我也要和你断开连接;发送方再回一个ACK给接收方。FIN是应用程序发送的,ACK是操作系统内核发送的。如果FIN前面还有一些复杂的逻辑要处理,FIN就会等一会儿再发送;如果没有,就可以和ACK一起发送。由于接收方的FIN和ACK在一些情况下不能一起发送,所以是四次挥手。以下是我画的简图:

TCP有几个常用的状态,分别是LISTEN,ESTABLISHED,CLOSE_WAIT,TIME_WAIT.这几个状态中其中TIME_WAIT是很重要的.主动断开连接的一方会进入这个状态,这个状态是为了等待一定的时间,等待这段时间是为了处理最后一个ACK丢包的情况.TIME_WAIT等待的时间是2MSL,MSL是操作系统中定义的一个常量,表示网络传输的过程中从一段传输到另外一个端的最大理论时间,一般来说默认值是一分钟,如果发现服务里里面存在大量的TIME_WAIT,这说明当前大量的连接都是服务器主动断开的.如果出现了最后一个ACK丢包的情况,那么超过等待时间之后,TIME_WAIT的状态会变成CLOSED,连接会直接销毁,操作系统会回收所有的内存和端口资源.

由于一问一答这种方式效率太低,所以设计TCP的大佬引入了滑动窗口来提升效率。滑动窗口就是发送方在发送数据的时候一次性发送多条数据,并给每一条数据编一个序号。比如发送了一千条数据,序号就是1-1000。接收方返回1001这个序号,代表前面的数据都收到了。由于有丢包的问题:如果是数据丢了,接收方不会返回对应的序号,发送方就会重新发送;如果是ACK丢了,比如丢的是1-1000的ACK,接收方就会一直发送1001给发送方,发送方发送到3001-4000的数据时,就会重新发送1-1000的数据,接收方收到之后返回4001,代表1-4000的数据都收到了。

滑动窗口不可能是无限大的,所以引入了流量控制和拥塞控制两个机制来控制滑动窗口的大小。接收方有一个队列用于接收数据:队列很空的时候,流量控制会把滑动窗口变大;队列空间很小的时候,就会把滑动窗口变小。拥塞控制是通过慢启动来控制窗口大小的:滑动窗口从一个很小的窗口慢慢变大,呈指数级增长,到达一个阈值之后就变成线性增长;当丢包之后,就会把滑动窗口的大小变成丢包时窗口大小的一半。最后取两个窗口中最小的一个来使用。

        捎带应答是配合延时应答一起使用的.那么什么是延时应答和捎带应答呢.

        每次发送方发送数据到接收方的时候,接收方都会间隔一段时间在发送ACK给发送方,这样可以少发一点ACK,并且丢掉一小部分ACK问题并不大,可以减少一部分的开销.这是延时应答,如果服务器计算响应已经完成,恰好这个时候ACK还没有发送给发送方,那么这个时候就会把ACK和响应合并成一个数据包发送给发送方.

        TCP的第九个机制就是面向字节流,就是因为这个机制,所以TCP在传输数据的过程中会有粘包问题的存在.比如发送一个数据”aaassxasascx”,TCP想怎么读都可以,边界并不明确.想要解决这个问题,我们可以引入一个特殊符号作为分隔符,TCP在传输的时候,如果遇到了这个特殊符号,就可以从这里进行分割.另外一个方法就是在数据开头的地方添加一个属性,用于标识数据包的长度.

        异常就是TCP对于进程崩溃,主机关机(正常流程关机),主机关机(断电关机),网线断开这几种情况的处理.

以上是我对TCP协议十个核心机制的粗略理解.

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐