上篇文章介绍了TCP可靠传输主要依靠的确认应答和超时重传机制,超时重传是确认应答的重要补充,还介绍了TCP的连接管理机制。本篇文章补充上一篇文章的TCP十个常用核心机制的其他七个。
目录
滑动窗口
TCP除了可靠传输外还希望能提高传输的效率,滑动窗口的设计就是为了来提高TCP的传输效率的机制。
不引入滑动窗口的时候传输过程是主机A发给主机B一组数据,再收到该组数据确认应答后A再发下一组,这样就很传输的效率就很低
引入滑动窗口后就会将一条一条发的效果转换成一批一批发的效果
窗口大小
不等待应答的ACK而批量发送的数据,这些数据的大小称为——窗口大小
当主机A批量发送了四组数据后等待ACK,收到第一组数据的ACK后窗口就会向前滑动,也就是发送5001~6001数据且等待第二组数据的ACK。此时要等待的数据仍然是四组,这就是窗口大小。
还有一种情况,发送方最先收到的是3001,此时代表的意思就是<3001的数据都收到了,这个时候窗口可以向前滑动两格。
滑动窗口出现丢包怎么办?
依然要保证可靠性
情况一:数据包到达了,ACK丢了
此时依靠滑动窗口的确认序号可以巧妙解决这个问题,假如说第一组数据1~1001的ACK丢了但是返回了2001,这个时候就涵盖了第一组数据的ACK,这种情况可以不做任何处理。
情况二:数据包丢了
接收方一直未收到第二组数据包导致在接下来的每次确认应答中都在索要1001~2000的数据,发送方在连续收到若干个相同的ack后就懂了有一组数据包丢失了,就会重新发送该组数据。
上述对于丢包的处理是非常高效的,对于ack丢了不必处理,对于数据包丢了,因为接收方的数据缓冲区会保留发送过的数据,所以只需要重传丢失的数据即可。这样的机制称为——快速重传,是滑动窗口下对于丢包处理使用的重传机制。
那么对于超时重传与快速重传是否会冲突呢?不会
这两种重传方式的应用情景不同,当传输的数据较少时不会触发滑动窗口,这个时候发生丢包时使用超时重传来处理,当传输的数据量很大时才会触发滑动窗口,这个时候使用快速重传解决,快速重传可以算超时重传的一种变种。
结论:滑动窗口是TCP提高效率的一种方式,但就算这样效率肯定还是远远不如UDP这种不可靠传输的效率高。TCP为了提高可靠性做出了很多的牺牲,滑动窗口是为了让牺牲减少一些。
流量控制
窗口越大的一次传输的数据就越多,传输的效率就越高,通常情况下我们是希望传输的效率越高越好,但提高效率的同时也要保证可靠性,如果发送方发送的太快,接收方处理不过来了也是一件麻烦事,此时接收方就可以告诉发送方发送的速度慢一点。
这种接收方根据自身的处理能力反向制约发送方发送速度的机制称为——流量控制
接收方有接收缓冲区来存储接收的数据,此时这个区就分为未使用的区域和已使用的区域,接收方在返回应答报文时就会将未使用的区域大小返回给发送方,这个返回的报文中的16位窗口大小就是来保存这片空余的区域。
那么16位窗口大小只能存储64kb吗?不是的。在报文中的“选项”中有一个特殊的属性——窗口扩展因子,实际的窗口大小 = 窗口大小<<窗口扩展因子,这个实际的窗口大小其实是非常大的。
16位窗口大小只会在ACK应答报文中生效,用来表示接收方接收缓冲区空余空间的大小。
当接收缓存区满了后就会告诉发送方停止发送,而停止发送就会导致无法收到应答报文而无法知道此时接收缓存区的情况,发送方就会周期性的发送一个窗口探测报文(不携带任何业务相关的数据),目的是触发应答报文ACK来了解此时接收缓存区的情况。
拥塞控制
流量控制是站在接收方的角度来控制发送方的发送速度从而避免出现问题,拥塞控制是考虑传输过程中中间节点来控制传输速度。二者都是搭配滑动窗口使用
流量控制很容易通过计算接收方缓存区大小来发送窗口大小,而如果考虑中间节点就复杂了,要考虑中间有多少设备/走的路径等问题,TCP不管中间有多么复杂的情况,只把他们当成一个整体,通过实验的方式来找到一个合适的窗口大小。
刚开始按照小的速度来传输数据,如果没有出现丢包则加快速度,扩大窗口大小;扩大到一定程度时传输速度已经非常快了,此时某个设备可能达到瓶颈期出现丢包的情况,则发送方立即降低速度减小窗口大小,如果不丢包继续加,丢包继续减,这样就可以找到一个合适的速度,既不丢包也可以保证较快的速度进行传输。
由于网络是复杂的,情况是多变的,通过上述方法随时适应网络中的变化。
拥塞控制会控制窗口大小,流量控制也会控制窗口大小,对于实际窗口大小应该听从其中较小的一个大小。
延时应答
在四次挥手中提到可以将ACK与FIN一起返回的机制——延时应答
延时的目的:提高传输效率。提高传输效率的核心是窗口大小,通过延时的方式给应用程序更多处理时间,也许原本直接返回ACK时缓冲区的空闲空间是1000,通过延时应答,应用程序进一步处理一些数据,此时返回的缓冲区空闲空间也许可以达到3000。
延时的时间计算方式有两种:(1)固定的时间 (2)按照一定的数据量;通常情况下是这两种数据相结合的方式来使用。
捎带应答
建立在延时应答的基础上进一步提高效率。
正常来说客户端与服务器是一问一答的方式,客户端发出请求后服务器先返回ACK,处理完请求后返回响应数据。如果此时ACK在处于延时应答中,刚好有要返回的响应数据,就可以顺便把ACK也返回(在TCP报头中把ACK和窗口大小都设置上),这样传输将两次返回合并为一次返回,也提高了效率。
面向字节流
在字节流读写的场景中会涉及到一个问题“粘包问题”。客户端向服务器读写多次时,可能出现服务器无法区分哪到哪是一个应用层数据包。
此处粘的是应用层数据包,主要目的是区分哪里到哪里是一个完整的应用层数据包,明确包之间的界限。有两种方式:(1)明确分隔符 (2)约定包的长度
异常情况
第一种情况:进程崩溃。无论正常结束还是进程崩溃,操作系统都能正常回收释放掉对应的PCB,可以释放其中的文件描述符表也就相当于调用close,此时会正常进行四次挥手。虽然进程不在但操作系统仍然管理着tcp的连接,仍可以进行四次挥手。
第二种情况:某个主机关机。正常关机的情况下操作系统会先尝试结束所有的进程再进行关机,这样这种情况本质上就是第一种情况。如果主动FIN后未走完流程就关机了的话,假设A给B发送FIN结束报文就关机了,B先回一个ACK之后准备发送FIN,因为A已经关机了无法回应ACK所以B的FIN就会多发几次,也会删除A的信息,而A这边已经关机了自然会把B的信息删除。
第三种情况:某个主机掉电。(1)掉电的是接收方:发送方发送完数据迟迟接收不到ACK就会触发超时重传,重传几次之后会发送复位报文RST,RST也没有响应那么发送方就会删除接收方的信息。(2)掉电的是发送方:接收方不知道发送方什么时候会发送数据,当沉默一会之后接收方就会向发送方发送一个心跳包,顾名思义用来探测对方是否挂了,心跳包的本质是一个没有载荷的数据包,目的是为了触发ACK,如果发送方正常就会返回ACK,如果连续若干次都没有响应那么接收方就会释放掉发送方的信息。实际开发中更经常使用应用层的心跳包。
第四种情况:网线断开。本质上是第三种情况,发送方的角度会触发超时重传,然后触发复位报文,最后单方面删除信息;接收方的角度会触发心跳包,无响应后单方面删除对方的信息。
到这TCP的十个常用核心机制就介绍完了,以上都是程序员需要掌握的基本功。
感谢观看
道阻且长,行则将至
标签:协议,窗口,重传,ACK,应答,JavaEE,TCP,发送,接收 From: https://blog.csdn.net/2301_78493961/article/details/141609023