目录
- 前言
- 1. TCP的超时重传机制
- 2. TCP的流量控制机制
- 3. TCP的滑动窗口机制
- 4. TCP的拥塞控制机制
- 5. TCP的延迟应答机制
- 6. TCP的捎带应答机制
- 7. 总结以及思考
前言
强烈建议先看传输层协议详解(上)后再看这篇文章. 上一篇文章讲到TCP协议为了保证可靠性而做的一些策略, 这篇文章会深度解析剩下的策略.
1. TCP的超时重传机制
主机 A 发送数据给 B 之后,可能因为网络拥堵等原因,数据无法到达主机 B;如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答,就会进行重发。这种操作叫做 超时重传。
就是我收到ACK,对方收到数据,但是,我没有收到ACK,对方没有收到数据.
不管是数据丢了,还是应答丢了,发送方的策略都是超时之后进行补发.
那么就有下面两个问题:
1.应答丢包后,发送方进行补发,那接收方就有两个一样的报文了,怎么去重呢?
一样的报文,说明32位序号是一样的,所以序号也有去重的功能!
并且,如果有不同的多个报文,序号也可以用来排序,使之按序到达.
2.那么,超时的时间如何确定?
这个时间的长短,随着网络环境的不同,是有差异的.
如果超时时间设的太长,会影响整体的重传效率;
如果超时时间设的太短,有可能会频繁发送重复的包。
2. TCP的流量控制机制
接收端处理数据的速度是有限的.如果发送端发的太快,导致接收端的缓冲区被打满,
这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应。
因此TCP支持根据接收端的接收能力,来决定发送端的发送速度,这个机制就叫做流量控制.
通过下面的若干个问题进行讲解:
- 接收方的接受能力是什么?
可以认为是: 接受缓冲区中剩余空间的大小!
- 发送方怎么知道对方的接受能力是多少?
发送方每次发送报文给接收方,接收方都会返回ACK应答,就是一个报头,此时接收方会把自己的剩余空间填入 16位窗口大小 这一字段,再返回给发送方!
- 那双方第一次发送信息的时候呢,又没有ACK应答,怎么控制?
三次握手期间,已经协商交换过了双方的接受能力!
- 16位窗口大小表示的数字最大是65535,那么 TCP 窗口最大就是 65535 字节么?
实际上,TCP首部40字节选项中还包含了一个窗口扩大因子M,实际窗口大小是窗口字段的值左移 M 位。
- 接收方的剩余空间为0了,发送方会等待,那过后接收方又有空间了,发送发送方怎么及时知道?
接收方会给发送方传递"窗口更新通知",其实就是一个报文,或是发送方间隔进行"窗口探测",也是一个报文。这两种方式一般是同时使用的。
- 那如果对方一直不进行窗口更新呢?
就要用到报头里的另一个标记位:PSH.就是告诉对方把缓冲区里的数据赶快取走.
当然,如果我们想让对方尽快处理数据,都可以设置PSH,不一定非要是0的时候.
这里再来讲一下最后一个标记位URG和16位紧急指针这个字段:
URG: 紧急指针标记位.URG置为0时,报头里的 16位紧急指针 这一字段无意义,置1时,才有意义.
16位紧急指针: 标识哪部分数据是紧急数据.
所以在流量控制机制中,我们学习了以下几个字段:
- 16位窗口大小
- PSH标记位
- URG标记位
- 16位进阶指针
3. TCP的滑动窗口机制
上篇文章中讲到, 服务器每收到一次数据都会回一个ACK确认应答. 但是这样是不是效率有点低下了?由其是数据往返时间比较长的时候. 有没有什么方法可以一次性发送多条数据呢? 当然TCP协议也考虑到了这一点:
滑动窗口:
可以将发送缓冲区想象成一个数组, 滑动窗口的本质就是此数组中的两个元素下标, 这两个下标会维护一段数据, 我们就可以将这份维护的数据一次性发给对方, 能大大的提高效率.
- 窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 上图的窗口大小就是4000个字节(四个段).
- 发送前四个段的时候, 不需要等待任何ACK, 直接发送;
- 收到第一个ACK后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;
- 操作系统内核为了维护这个滑动窗口, 需要开辟 发送缓冲区 来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;
- 窗口越大, 则网络的吞吐率就越高;
所以下面两个问题就有了答案:
(1)根据流量控制机制发送方已经知道了对方的接收能力,那具体该如何发送?
流量控制,就是通过滑动窗口实现的!
(2)在超时重传时,超时时间以内,已经发送的报文不能被丢弃,而是要保存起来!保存在哪里?
保存在滑动窗口中!
4. TCP的拥塞控制机制
虽然是TCP有滑动窗口这一大杀器来提高效率和可靠性, 但是我们始终在关心的是, 对端怎么怎么样, 对端的接受能力怎么样, 对端是否收到了信息. 我们从来没有考虑过网络本身的情况, 万一网络本身就不好, 还一次性发送了大量数据, 丢包了怎么办? . 当然这一切都在TCP协议的预料之中.
拥塞控制:
因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据,是很有可能引起雪上加霜的. TCP引入 慢启动 机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据.
其实你只用知道, TCP的拥塞控制是用来关心当前网络状态的, 并且它采用的慢启动机制, 虽然这其中还有很多细节可以挖掘, 但是作为从事后端开发的大学生而言, 学到这个地方已经是有点东西了.
(有兴趣的同学可以看看下面对"慢启动"的的图像以及一点理解)
5. TCP的延迟应答机制
若接收数据后立刻返回ACK应答, 返回窗口会比较小.
- 假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K;
- 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
- 在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
- 如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;
一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高. 我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;
说白了, 有时候立刻应答并不是一种高效率的体现.
6. TCP的捎带应答机制
捎带应答机制其实就是: ACK应答+数据 一起返回去.
要注意的是: 三次握手里的前两次握手是不能捎带应答的,因为此时连接还没有建立好,只有建立成功了才可以通信.但是第三层握手ACK可以捎带数据了.
至此,TCP协议报头里的所有重要字段及其它们的作用机制都讲解完毕!
7. 总结以及思考
现在再来看, TCP是面向字节流的就大概能理解了. TCP只管迅速的给对端发包, 不管一个数据要分几次发, 一次性发多少, 总之它只管尽快将包发过去. 换句话说,就是站在TCP的角度,没有报文的概念,所有的数据都是放在一个字符数组的缓冲区里,只是单纯的把数据推送过去,但是到底有没有推完一个,一个半…)都由网络决定.
虽然这样大大的提升了效率, 但是会带来粘包问题. 也就是说对端收到数据后, 它并不知道这个数据是否是完整的一个, 还是半个, 甚至是两个半都有可能.
TCP小结:
TCP和UDP的对比:
我们说了TCP是可靠连接,那么是不是TCP一定就优于UDP呢?
当然不是! TCP和UDP之间的优点和缺点,不能简单,绝对的进行比较。
(1)TCP 用于可靠传输的情况,应用于文件传输,重要状态更新等场景;
(2)UDP 用于对高速传输和实时性要求较高的通信领域,例如,早期的 QQ,视频传输等。另外 UDP 可以用于广播;