TCP核心机制
上一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(三)
书接上文~
TCP核心机制四: 滑动窗口
为啥要使用滑动窗口?
之前我们讨论了确认应答策略,对每一个发送的数据段,都要给一个ACK确认应答.收到ACK后再发送下一个数据段.这样做有一个比较大的缺点,就是性能较差,尤其是数据往返的时间较长的时候.
既然这样一发一收的方式性能较低,那么我们一次性发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了).
这里的提高效率,只是"亡羊补牢",使传输效率的损失,尽可能降低,引入滑动窗口,不能使传输效率比UDP还高的~
滑动窗口介绍
改进方案:
- 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,上图的窗口大小就是4000个字节(四个段).
- 发送前四个段的时候,不需要等待任何ACK,直接发送.
- 操作系统为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答,只有确认应答过的数据,才能从缓冲区删掉.
- 窗口越大,则网络的吞吐率就越高.
滑动窗口出现丢包咋办?
滑动窗口的前提,是可靠性,如果在滑动窗口传输中,出现丢包,咋办??
-
情况一: 数据包已经到达,ACK被丢了.
在这种情况下,我们不需要做任何处理.
批量发数据,批量ACK,多个ACK,只是丢其中的一部分吧,不可能全丢.为啥不做处理?
要想搞清楚这个问题,我们首先要理解确认序号的含义.
确认序号表示的是收到的数据最后一个字节的下一个序号.
进一步可以理解成,确认序号之前的数据,主机B都已经收到了.接下来你要发的数据就从确认序号这里往后发就行了~举个例子,虽然1001 ACK丢了,但是2001 ACK到达了.发送方收到2001之后,意味着2001之前的数据都已经收到哩~
也就是说,后一个ACK能够涵盖前一个ACK的意义~ -
情况二: 数据包就直接丢了.
- 当某一段报文段丢失之后,发送段会一直收到1001这样的ACK,就像是在提醒发送端,"我想要的是1001"一样.
- 如果发送端主机连续三次收到了同样一个"1001"这样的应答,于是主机就会意识到1001数据丢包了,就会将对应的数据1001-2000重新发送.
- 这个时候接收端收到了1001之后,再次返回的ACK就是7001了(因为2001-7000)接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中.
这种机制被称为"高速重发控制"(也叫"快重传").
TCP核心机制五: 流量控制
滑动窗口的窗口大小,对于传输数据的性能是直接相关的.
那么问题就来了,窗口大小能无限大吗?
通信,是双方的事情,发送方发的快了,你也得确保,接收方能处理过来啊~
接收方处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应.
TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制.
流量控制,不是TCP独有的机制.其他的协议也可能会涉及到流量控制(比如,数据链路层中有的协议,也支持流量控制~)
- 接收端将自己可以接受的缓冲区大小放入TCP首部中的"窗口大小"字段,通过ACK端通知发送端.
- 窗口大小字段越大,说明网络的吞吐量越高.
- 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端.
- 发送端接受到这个窗口之后,就会减慢自己的发送速度.
- 如果接收端缓冲区满了,就会将窗口设置为0,这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,来让接收端把窗口大小告诉发送端.
接收端如何把窗口大小告诉发送端呢?回忆一下我们之前提到的TCP首部.
在TCP首部中有一个16位窗口字段,这里就存放了窗口大小信息.
16位窗口字段这个属性,只有在ack这一位位1时才有效~
窗口大小,此处是16位,它能表示的范围0~64kb,这是否意味着发送方窗口大小最大就是64kb呢?
不是的!!
其实,在TCP首部的选项中,可以设置一个特殊的选项,“窗口扩展因子M”.
实际的窗口大小是窗口字段的值左移M位~
下一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(五)
本文到这里就结束啦~