本篇将描述TCP的重要的机制:确认与重传机制(重点)、滑动窗口(重点)、流量控制、拥塞控制、延迟应答、捎带应答、粘包问题和面向字节流。
(1)SeqNo和AckNo
计算机A是最初发起建立TCP会话的一方。A首先要产生一个随机 整数X,这个x被称为A的初始序号(ISN, Initial Sequence Number)o A向B发送的第 一个TCP分段是一个SYN分段,这个SYN分段中的SeqNo就等于X。
B在收到A发送的SYN分段后,会回应一个SYN+ACK段。B也会产生一个随机整数 y,这个v就是B自己的初始序号ISN,在B回应的SYN+ACK段中,SeqNo的值就是 y。同时,SYN+ACK段中AckNo的值为 x 的值加上1。
最后,A回应一个ACK分段给B。在这个ACK分段中,SeqNo的值为 x 的值加上1, AckNo的值为 y 的值加上1。至此,TCP会话的建立过程便告结束。
(2)确认与重传机制
假设A与B建立了 TCP会话之后,A有很多个TCP数据段需要传递给B。假设A 需要传递的第一个数据段的长度是400字节,第二个数据段的长度是500字节,第三个数据段的长度是800字节。另外,假设A的初始序号x为 1367。
A完成了第三次握手(向B回应了一个ACK分段)之后,便可以开始发送第一个 数据段。A在发送第一个数据段时,数据段的SeqNo应该为1369,因为1367和1368 已经在三次握手过程中被A使用过了。注意,1369其实是第一个数据段的第一个字节的序号。第一个数据段的最后一个字节的序号是1 768 (1 369 + 400 - 1 = 1768).。A在发 送完第一个数据段后,便开始等待来自B的确认信息。
B在成功接收到了第一个数据段后,会向A回应一个ACK段。这个ACK段的AckNo 的值为1769 (1369 + 400=1769),它的含义是:我希望下次开始接收序号为1769的字节,因为我已经接收到了序号为1768之前的所有字节。
A收到B回应的ACK段后,就开始发送第二个数据段。发送第二个数据段时,数 据段的SeqNo为1 769。注意,1 769其实是第二个数据段的第一个字节的序号。第二个 数据段的最后一个字节的序号是2 268 (1 769+500-1 =2 268). A在发送完第二个数据 段后,又开始等待来自B的确认信息。
B在成功接收到了第二个数据段后,又会向A回应一个ACK段。这个ACK段的 AckNo的值为2 269( 1 769+500=2 269),它的含义是:我希望下次开始接收序号为2 269 的字节,因为我己经接收到了序号为2 268之前的所有字节。
A收到B回应的ACK段后,就开始发送第三个数据段。发送第三个数据段时,数 据段的SeqNo为 2 269。注意,2 269其实是第三个数据段的第一个字节的序号。第三个 数据段的最后一个字节的序号是3 068 (2 269+800 — 1 =3 068)。A在发送完第三个数据 段后,又开始等待来自B的确认信息。
B在接收到了第三个数据段后,又会向A回应一个ACK段。这个ACK段的AckNo 的值为3 069 (2 269+800=3 069),它的含义是:我希望下次开始接收序号为3 069的 字节,因为我已经接收到了序号为3 068之前的所有字节。
A收到B回应的ACK段后,就开始发送第四个数据段。发送第四个数据段时,数 据段的SeqNo为3 069……
假如,A发送的第二个数据段在传递过程中丢失了(比如,A发出的某个帧在传递 过程中丢失了,这个帧封装了一个IP包,而这个IP包封装了这个数据段),那么B就不可能向A回应相应的ACK段。因为A没有接收到B对这个数据段的回应,所以A就不能开始发送第三个数据段。A能做的事情就是继续等待B对第二个数据段的回应。当A 的等待时间超时后,A就会认为B没有成功接收到第二个数据段。于是,A就会重新发送第二个数据段,然后重新等待B的回应。
(3)滑动窗口
确认与重传机制的基本特征:A每发送一个数据段,都必须等待B的一个确认(回应),所以传输效率很低。
为了解决这个问题,TCP协议还提供了一种被称为“滑动窗口 (Sliding Window) “的机制来提高传输效率。
【1】确认与重传机制
【2】滑动窗口
我们可以一次发送多条数据,这样就可以大大的提高性能。这样做的本质其实就是将多个段的等待时间重叠在一起了。
窗口大小指的是无需等待确认应答而可以继续发送的数据的最大值,这个最大值由接收方的接收缓冲区大小决定。上图所示的窗口大小即为4000个字节(四个段)。窗口越大,则网络的吞吐率就越高。
当主机A收到5001的应答,但未收到3001、4001的应答时,我们可以考虑两种情况:
(1)3001、4001的应答较慢,5001的应答较快,所以先到达;
(2)3001、4001的应答丢失了;
这两种情况其实都不影响,因为收到5001的应答,就表示前5000个数据全收到了。
在滑动窗口中,如果出现了丢包,如何进行重传呢?我们还是分两种情况来讨论:
(1)数据报已经抵达,ACK被丢失了;
在这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认,也就是我们上面举得这个例子。
(2)数据包直接丢失了;
当某一段报文段丢失以后,发送端会一直收到1001这样的ACK,就像是在提醒发送端“我想要的是1001”一样。
如果发送端主机连续三次收到了同样一个“1001”这样的应答,就会将对应的数据1001~2000重新发送。
这时接收端收到了1001以后,再次返回的ACK就是7001了。因为2001~7000接收端其实之前就已经收到了,被放到了接收端操作系统内核的接收缓冲区中。
这种机制被称为“高速重发控制”,也称为“快重传”。(快重传其实是超时重传的一种优化。)
(4)流量控制
接收端处理数据的速度是有限的,如果发送端发的太快,导致接收端的缓冲区被打满,这时如果发送端继续发送,就会造成丢包问题,继而导致丢包重传等等一系列连锁反应。因此TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。
(5)延迟应答
如果接收数据的主机立即返回ACK应答,此时返回的窗口可能比较小。假设接收端缓冲区为1M,一次收到了500K的数据,若此时立即应答,则返回的窗口大小为500K。但实际上可能处理端处理的速度非常快,几毫秒内就能将数据从缓冲区消费掉。在这种情况下,接收端处理还远未达到自己的极限,即使窗口大小再大一些,也能处理的过来。如果接收端稍微等一会再应答,比如等待几百毫秒再应答,那么此时返回的窗口大小就是1M。
窗口越大,网络吞吐量就越大,传输速率就越高。我们的目标就是在保证网络不拥塞的情况下尽量提高传输效率。
也不是所有的包都可以延迟应答,这是有数量限制和时间限制的。所谓的数量限制,就是每隔N个包就应答一次;所谓的时间限制,就是超过最大延迟时间就应答一次。而具体的数量和超时时间,依操作系统不同也有差异。一般来说N取2,超时时间取 200ms。
简而言之,就是主机A发送的数据,在主机B收到A的数据之后,主机B不是没收到数据就回复,而是按着一定的规律回复;
(举个例子:以前,我都是每次说“Hello”,你就马上的回复“Hi”,也就是“Hello”,“Hi”;“Hello”,“Hi”的规律
现在是,我每次说“Hello”,但你心里打个小算盘,要我每说两次“Hello”,你才回复“Hi”。也就是“Hello”,“Hello”,“Hi”;“Hello”,“Hello”,“Hi”的规律)
(部分转载于并且推荐:https://blog.csdn.net/Cecilia3333/article/details/80358201)