确认应答机制
确认应答机制是保证TCP可靠性的核心机制;
确认序号在TCP中表示接下来想要的下一条数据编号,而不是当前收到的数据编号;
发送方收到应答数据的时候,应答报文中的确认序号为1001,此时发送方就知道1-1000的数据已经顺利抵达,接下来要发送的数据是从1001开始;
应答报文中ACK这一位为1,说明当前确认序号是有效的。
超时重传
可靠性就是为了应对丢包,针对丢包情况进行重传数据。应答报文发送失败,发送方会继续发送报文,直到接收方发送应答报文被发送方收到。(这个过程中在一定时间内没有收到应答报文时才会重传)。
重传时的发送报文会和之前的重复,
but
TCP自身已经处理好了这种数据重复的情况,TCP有一个“接收缓冲区”(一块内存),TCP就会根据序号检查缓冲区中有没有重复的数据,并去重。
丢包有一定的概率,超时重传等待的时间间隔不是固定的,而是逐渐变大的。假设丢包率的概率是固定值,此时连续丢包的概率比较小。若出现连续丢包,大概率是网络出现了彻底的问题,所以TCP重传的时间间隔就会越来越高,频率会越来越低。(!重传到一定的次数,就会尝试断开连接)
TCP的可靠性依赖于“超时重传+应答机制”。
连接管理
TCP建立连接(三次握手)
三次握手的本质:确认通信双方的发送能力和接受能力都正常。(可靠性的基础)
- 第一次握手:接收方知道发送方的发送能力正常;
主机A——>主机B:SYN - 第二次握手:发送方知道自己和接收方的发送能力正常;
主机B——>主机A:SYN+ACK - 第三次握手:接收方知道自己的发送能力和发送方的街火速能力
主机A——>主机B:ACK
(SYN为1,就是同步报文段)
TCP断开连接(四次挥手)
-
建立了连接,就需要在操作系统内核中来维护这些连接,用一些数据结构或者对象来保存连接相关的信息,并为后面的通信进行服务;
-
双方各自向对方发送FIN,并向对方回应ACK
-
断开连接时,主机B给主机A回复的ACK和FIN
1.可能合并在一起:如果close()能够被很快的调用到(FIN和ACK的时间间隔不是很长的时候就会触发TCP的“延时应发+捎带应答”机制)
2.也可能不合并:发送ACK和FIN的时机不一样。发送ACK是操作系统内核行为,在收到FIN的第一时间就回复ACK;发送FIN是应用程序的行为,在代码中执行到对应的“close()”才会触发FIN。 -
在三次握手和四次挥手之间也会涉及到确认应答和超时重传
-
TCP协议的一些核心状态
1.ESTABLISHED连接成功,可以进行后续通信了;
2.LISTEN服务器端进入的状态,表示服务器准备就绪,允许客户端随时来建立连接;
3.CLOSED_WAIT断开连接时的中间状态,这个状态正常情况下存在时间较短。出现在收到FIN,返回ACK到发送FIN这个时间间隙中。一般看到这个状态是,可能是代码出bug了,导致没有及时调用到close方法
4.TIME_WAIT也是断开连接时的状态。谁主动断开连接,谁进入该状态。(建立连接只能客户端发起连接请求;断开连接时,客户端和服务器端都可以做)。该状态存在的意义是为了防止最后一个ACK丢包做准备的,当进行最后一个ACK发送完成之后,并不会立刻销毁连接,而是以这种状态等待一段时间。一定时间之后,发现对方没有重传FIN,就视为ACK没丢包,然后真正的释放连接。(等待时间为2MSL,MSL表示网络中两个主机之间传输数据的最大间隔)
滑动窗口
-
保证可靠性也要提高传输效率。确认应答如果等到ACK到达之后再发送数据,效率比较低,可以让发送方批量的发送一组数据,同一等待ACK,这组数据的数据量称为窗口大小。
-
窗口范围内的数据就是已经发出去的数据,同时也是要等待ACK的数据,随着对方ACK的到达,要等待的数据也就随之变化,同时也会发送新的数据出去。
-
这里的重传机制得益于确认序号的设计,保证了较高的传输效率
-
窗口越大,传输效率越高,内存消耗就更大;窗口越小,传输效率越低,内训消耗更小。
-
影响串口大小的其他因素:接收方的处理速率(即应用程序从队列中取的速度快慢)。此时就需要根据接收方的处理能力限制发送方的窗口大小。
流量控制
- 发送方先有一个初始的窗口大小。发送数据过去之后,对方返回一个ACK,其中包括确认序号和数据(接收方缓冲区的剩余空间大小)。
- 流量控制的目的一是为了让发送方和接收方的速率尽可能步调一致,才能做到可靠地同时尽量高效。
- 接收方根据自己的处理能力,方向控制发送方和发送速率。
- 复杂的网络环境中,不仅要考虑接收方的处理能力还要考虑中间结点的处理能力。
拥塞控制
- 滑动窗口大小是由拥塞控制和流量控制一起决定的
- 由于网络环境比较复杂,发送方采取一个动态变化的过程,来试探出当前的窗口大小多少合适,会在初始情况下设置一个比较小的窗口大小,发数据,如果没丢包,网络是畅通的,就会扩大窗口大小,循环,直到丢包再缩小窗口。
- 滑动窗口的实际大小,就是拥塞窗口和流量控制窗口的较小值。
延迟应答
接收方收到发送方的数据之后,并不是立刻返回ACK,而是等待一会(500ms)再返回ACK,ACK携带的窗口大小可能会更大,这500ms中农应用程序可能从缓冲区中取走了一些数据。
捎带应答
最常见的服务器通信模式——一问一答。
因为延时应答的原理。应用程序返回响应的时候,顺带把上个ACK数据也一起携带过去,减少了传输的数据包个数,减低了通信成本,提高了效率。
面向字节流
- 粘包问题不是TCP独有的问题,只要是面向字节流都会涉及到年报,面向数据报的UDP就没有这个问题
- UDP的接收方以每个数据包为单位组织的数据,每个数据报都相当于链表的节点
- 解决粘包问题:显式的指定包的长度;显式的指定包和包之间的分隔符(结束标记)
- GET请求,通过“结束标记”来区分不同的包的(空行),指定body长度。
TCP对于异常情况的处理
-
进程终止:进程终止会释放文件描述符,仍然可以发送FIN,和正常关闭没有什么区别。
-
机器重启:和进程终止的情况相同。
系统会先杀死进程,触发四次挥手,注:主机B还没挥手完成,主机A已经关闭,主机B会以LAST_ACK状态尝试重传几次FIN,一直没有ACK之后,也就释放了连接。 -
机器掉电/网线断开:
接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行reset,即使没有写入操作,TCP也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放。 -
负载均衡,哪些节点是正常工作的,哪些节点是出现问题的,心跳包是判断的依据。负载均衡可以在服务不中断的情况下对服务器进行重启和升级。