可靠性
- 基于数据块传输:TCP会把应用层传下来的数据,分割成合适的块再进行传输
- TCP三次握手:对报文序号进行校验
- ARQ自动重传协议:超时重传
- 流量控制
- 拥塞控制
理解
TCP是一个可靠的端到端传输协议。它通过建立连接、按序收发、丢包重传、流量控制、拥塞控制等方式来保证传输的可靠性。建立连接时确保双方的收发能力并互相同步初始序列号,初始序列号的同步保证之后的按序收发和重传能够实现。流量控制是发送方根据接收方的接收能力来控制发送报文段的数量,这样能够减少因接收方缓存不够而丢包的情况。拥塞控制是根据整个网络链路的情况,来控制发送数量。
TCP三次握手
三次握手的目的是为了通过同步双方数据的序列号来保证可靠传输。 保证双方的收发能力、阻止重复历史连接的初始化。
握手过程
- C发送同步信号位SYN = 1和原始序列号x。发送后客户端进入
SYN_SEND状态。 - S接收到C发送的原始序列号,记在本地,并标记确认序号ack = x + 1,和确认信号位ACK = 1。发送后服务端进入
SYN_RECV状态。 - S也需要告知C自己的原始序列号,同样发送SYN = 1和原始序列号y。
- C收到S的原始序列号后,记在本地,并标记确认序号ack = y + 1,和确认信号位ACK = 1。客户端进入
ESTABLISHED状态。
上述过程的2.3两步合并,所以就形成了三次握手。 看了上面的过程就知道为什么一定要三次握手,因为双方都需要确认对方已经同步自己的原始序列号。
握手时会出现的异常
- 当第一次握手丢失,C会进行超时重传,重传次数和超时时间都是内核参数决定的。
- 当第二次握手丢失,这时候会影响到C和S双方。C会以为自己的包没有发送,进行超时重传;S没有收到C的确认也会进行超时重传。
- 当第三次握手丢失,这时候S会认为自己的报文没有送达,进行超时重传。而C在发送完第三个握手后,就进入了
ESTABLISH状态,并且ACK报文不会重传,所以不会管这个异常。
关于序列号的更新
TCP规定SYN和FIN报文即使没有内容也是占一个序列号,而ACK报文可以携带数据,但如果不携带数据则序列号不增。所以第三次握手后,A发送数据时序列号与第三次握手的相同。
四次挥手
挥手过程
- C发送释放报文FIN = 1、seq = u,告知服务器将要结束会话,并且之后不会再发送数据。发送后客户端进入
FIN_WAIT1状态。 - S收到C的释放报文,返回一个确认报文,ACK = 1,ack = u+ 1,seq = v。但此时没有立刻结束,因为S可能还有数据要发送,而C也要继续接受S的数据。发送后服务端进入
CLOSE_WAIT状态。 - 客户端收到服务端的ACK后,进入
FIN_WAIT2状态 - S发送完数据后也可以释放会话了,就发送释放报文FIN = 1、seq = w、ACK = 1,ack = u+ 1。发送后服务端进入
LAST_ACK状态。 - C收到S的释放报文后,返回确认报文ACK = 1、ack = w + 1、seq = u + 1,然后进入
TIME_WAIT状态,并等到2*MSL后才进入CLOSED状态。 - S只要收到了C的确认报文,立刻进入
CLOSED状态。
为什么需要四次挥手
与三次握手一样,需要保证双方都知道结束会话这个消息;与三次握手不同的是,挥手时2、3两步无法合并成一步,因为S可能还有数据没传完。
为什么要等待两个MSL
MSL是最长报文段寿命。为了防止返回的确认报文丢失,如果确认报文丢失,则S会超时重传释放报文,能够在两个MSL内重新发送到C,C就再一次发送确认报文并重新开始计时。【思考:如果S第二次发的报文丢了,那么C不会等S,会直接结束会话,怎么办?见异常分析】
挥手会出现的异常
- 第一次释放报文丢失,C会进行超时重传,和普通报文一样,重传机制由OS控制。
- 第二次确认报文丢失,ACK报文是不会进行重传的,而C没有收到就会重传释放报文。
- 第三次释放报文丢失,S会进行重传。如果此时C等待了一段时间一直没有收到S的释放报文,会主动关闭会话。
- 第四次确认报文丢失,S会进行重传,如果C此时已经结束会话,S也会在达到重传次数后认为异常,主动关闭会话。
流量控制
流量控制是针对接收方,确保接收方有足够的缓存来接收发送方的数据。 发送方维护一个发送窗口,接收方维护一个接收窗口,并且发送窗口是根据接收窗口来决定的。
发送窗口
可以分为四个部分:1、已发送已确认;2、已发送未确认;3、可发送;4、不可发送;
接收窗口
可以分为三个部分:1、已接收已确认;2、等待接收;3、不可接收
拥塞控制
拥塞控制针对整个网络的链路,确保发送方提供的数据量能够在网络中正常传送。发送方维护一个拥塞窗口,让发送窗口等于拥塞窗口,但实际上考虑到流量控制,还要与接收方的接收窗口对比,取较小值。
慢开始算法
拥塞窗口从1开始,每经过一个RTT(Round Trip Time:往返时间)就让拥塞窗口翻倍,这时候拥塞窗口是指数增长。
拥塞避免
在慢开始算法有一个慢开始门限ssthresh,当拥塞窗口超过这个值时,就开始拥塞避免算法。此时拥塞不是真的发生了,而是为了避免拥塞降低了拥塞窗口的增长速度。从每个RTT翻倍,变为每个RTT增加1。 当拥塞发生时(超时就可以被判断为拥塞),将ssthresh将为当前拥塞窗口的一半,并让拥塞窗口从1重新开始慢开始算法。
快重传
要求接收方接收到不期待的序号时,立即返回一个重复确认报文,当发送方收到三个相同序号的确认报文时,认为某个报文已经丢失,立刻进行重传。
快恢复
当拥塞发生时,不从1开始恢复拥塞窗口,而是降低到新的ssthresh,即拥塞发生时拥塞窗口的一半,然后进行线性增加窗口大小。
ARQ 自动重传协议
停止等待
发送一个报文就停下来,等待接收方给返回。在超时后没有接收到返回则自动重传。
连续
发送方维护窗口,一次性将窗口内的内容全部发送,根据接收方的返回来更新窗口。接收方可以使用累计确认来对接收到的最后一个报文进行确认,表明这之前的报文都正确接收了。
思考
二次握手可以吗?
不行。如果只有两次握手,服务端无法确保客户端的接收能力正常,且无法确保已成功与对方同步自己的初始序列号。
三次握手可以携带数据吗
第三次可以携带数据。客户端发出第三次握手时已经确保服务端的接收能力正常,因此可以放心的发送数据。
为什么不能是三次挥手
三次握手其实是将第二次和第三次握手合成了一次。而断开连接时服务端很可能还没结束数据传输,因此无法合成一步。
为什么要等待两个最长报文段寿命
防止最后一个确认包丢失,给服务端重传FIN报文留出时间。还能够避免新旧连接混淆,经过两个最长报文段寿命后,可以确保当前连接的报文都从网络中消失。
与UDP区别
UDP不面向连接,也不保证可靠的端到端传输。对应用层传下的数据报不进行处理,只进行简单的封装。由于不基于连接所以速度比较快,而且它的头部开销小,只有8B。