TCP核心机制详解(三)

目录

前言:

滑动窗口

滑动窗口处理丢包问题

流量控制

拥塞控制

延时应答

捎带应答

面向字节流

异常情况

小结:


前言:

    前两篇文章讲述了,TCP十种核心机制的前三种。这篇文章详细介绍其他的一些核心机制,让我们更深入理解网络原理。

滑动窗口

    由于TCP为了保证可靠性,引入了一些机制。这些机制必然导致TCP的效率降低。比如每发一个数据报就需要等待ACK(比较消耗时间)滑动窗口就是为了提高TCP的效率。

TCP核心机制详解(三)_第1张图片

    滑动窗口本质上就是降低了确认应答等待ack的时间(批量发送,批量等待)。对于基本的确认应答情况来说,每次发一个数据,都要等待ack。而滑动窗口的本质就是不等待的批量发送一组数据,然后使用一份时间来等待一组多个ack。这里把不需要等待就直接发送的数据称为“窗口大小”。 

    注意:这里在等待ack的时候,不是说等待所有的ack全部到达后才继续发送,而是只要到达一个ack就继续发送。那么窗口的大小始终都是不变的,同时也体现出 “滑动”的特性。

滑动窗口处理丢包问题

1)ACK丢了

    不需要做任何事情,只要后面的ack到达了,就可以证明前面的数据到达了。ACK返回的确认序号就是证明这个序号以前的数据已经成功到达。

TCP核心机制详解(三)_第2张图片

2) 数据包丢了

TCP核心机制详解(三)_第3张图片

解释:

    如果2001 - 3000的数据丢了,后面的ack都是2001。直到数据发送到7001 - 8000返回的ack也是2001(索要2001的数据)。这时候主机A发现丢包了,将2001 - 3000的数据包重新传一下,然后返回的ack就是8001(最新的索要序号)。就证明前面的数据发送完成。

    这样的重传方式叫做“快速重传”。如果传输数据密集,采用滑动窗口的方式,使用快速重传处理丢包。如果数据传输不是很密集,不按照滑动窗口的方式,就是一般的超时重传。

流量控制

    滑动窗口越大,传输效率就越高(一份时间等待的ack就越多),但是窗口也不能无限大。需要根据接收方处理数据的能力来控制窗口的大小。

    衡量接收方处理数据的能力,直接查看缓冲区剩余空间的大小。

    每次发送方发送数据,接受方返回的ack就会携带,根据缓冲区剩余空间大小计算的窗口大小。选项中存在“窗口扩展因子”,接收的窗口值再左移窗口扩展因子位。(为了使窗口足够大,效率做到最大的提升)

注意:

    由于接收方缓冲区大小是动态变化的,那么对应的窗口大小也是动态调整的。

    当窗口大小为0的时候,发送方就会等待。在这个时间里,发送方会发送“窗口探测报文”触发ack查询窗口大小。

拥塞控制

    网络传输中中间需要经历很多节点,现在只考虑了接收方处理数据的能力,如果中间哪个节点处理数据的能力较低,那么总体效率也不会高(木桶效应)。

    流量控制和拥塞控制共同决定窗口的大小。流量控制考虑的是接收方处理数据的能力。拥塞控制考虑的是中间节点处理数据的能力。

    拥塞控制,就是在网络中发生拥塞时(路由器处理数据慢),减少向网络中发送数据的速度,防止造成恶性循环;同时在网络空闲时(路由器处理数据快),提高发送数据的速度,最大限度地利用网络资源。

    由于每次网络传输的中间节点都是不固定的。因此没办法衡量中间节点的处理数据的能力。采用 “实验” 的方式。

TCP核心机制详解(三)_第4张图片

注意:

    开始是指数增长,当窗口达到一定大小就变为线性增长。当传输过程一旦丢包了(网络拥塞),说明窗口大小已经是极限了。此时就把窗口大小一下缩小为很小的值(重复刚才的指数增长和线性增长)。

    拥塞窗口不是固定的数值,而是一直动态变化的。随着时间推移,逐渐达到一个相对平衡的状态。        

    拥塞窗口和流量控制共同决定了发送发实际的窗口大小(窗口大小取两者的较小值)。

延时应答

    在滑动窗口的基础上,尽可能的扩大窗口的大小。

    所谓延时就是收到数据后,不是立即返回ack而是稍等一会再返回。等待的时间里,接收方程序就能够把缓冲区的数据处理一波,此时剩余空间就大了,那么发送方窗口也就大了。

    实际上延时应答的具体做法,就是在滑动窗口下,ack不在每一条数据都返回了。比如隔一条返回,相对于第一条数据这里的ack就等于等待了。

TCP核心机制详解(三)_第5张图片

捎带应答

    本来ack和要返回的业务数据不是同一时机,但是在延时应答的机制上,可能就会在同一时机。然后就会合并为一条报文发送过去。提高效率的方式。

TCP核心机制详解(三)_第6张图片

面向字节流

    TCP的特点就是面向字节流。面向字节流,就引出了一个问题:粘包问题。进行read读取的时候,读到哪里才算结束呢?读到哪里才算一个完整的数据包呢?

解决方案:(需要自己代码实现)

    1)约定好分隔符,当读到分隔符就结束。

    2)约定好每个包的长度,只读取这么长的数据。

异常情况

1)进程崩溃

2)主机关机

3)主机掉电

4)网线断开

注意:

1)

    进程没了,对应的pcb也就没了,对应的文件描述符表也就释放了,相当于Socket.close()。此时内核就会完成四次挥手,也就是正常的断开流程。(主机关机,首先关闭进程,和这里原理一样)。

2)

    假设接收方掉电,发送方等不到ack,然后超时重传多次,依然失败。接下来断线重连(RST复位报文段)还是失败,就单方面放弃了。

    假设发送方掉电,接收方发现没有数据了,先等。这个时候会周期性的发送 “心跳包” 确认对方是否工作正常。(心跳包来确认通信双方是否处在正常的工作状态)

小结:

    TCP核心机制到这里就结束啦,TCP是一个很复杂的协议还有很多的机制。需要继续了解可以去查阅官方文档。

你可能感兴趣的:(JavaEE,tcp/ip,网络,服务器)