深入理解TCP的10种机制
1. 确认应答
1.1 基本原理
- 发送方发送一个数据给接受方,
- 接受方接收到数据之后,就给发送方一个应答
- 发送方接收到这个应当之后,就知道接受发收到了它发送的数据。
1.2 序号和确认序号
因为数据在传输过程中,可能会出现**“先发后到”的现象,所以就需要引入序号来标识数据的先后顺序**。
1.3 确认应答机制的地位
确认应答是TCP协议中,保证数据可靠性传输的核心。
2. 超时重传
2.1 网络传输中的丢包现象
数据在网络中传输时,可能由于网络的不稳定,导致数据的丢失。
丢包会导致网络十分卡顿。
丢包的两种情况:
2.1 超时重传
如果数据发出去一段时间了,但是并没有收到确认应答,就说明可能发送了丢包现象,此时就需要重新传一下数据。
2.3 超时重传的时间设计
如图所示:超时时间随着丢包次数的增多而增加。
如多丢包次数过多(超过三次),就说明大概率是连接出了问题,此时就可以放弃连接。
3.
- 三次握手
- 四次挥手
详见:三次握手、四次挥手
详见这篇文章:
4. 滑动窗口
4.1 滑动窗口的作用
滑动窗口的引入是为了提供TCP传输数据时的效率。 滑动窗口的本质就是批量发送,滑动窗口的大小就是一次性批量发送的数据量多少。
在前面我们所举的例子当中,数据都是以这种方式进行传输的:
但是,在这种传输方式中,大多数的时间都是发送方等待接收方的确认应答,效率极其不高。
所以,我们便改进位下面的传输方式:
这样的话,就可以减少等待时间。
这就好比:去小吃街买吃的
4.2 窗口如何滑动
这里的确认号表示:该序号之前的所有数据都收到了
4.3 数据“先传后到”的情况分析
4.4 丢包情况分析:
ACK丢包
这种情况发生时,并不会有太大的影响,只要ACK别丢的太多就行。
如图:ACK=1001丢了,滑动窗口最左侧就不会滑动到1001,但是ACK=2001被主机A正常接收到,此时滑动窗口最左侧就会直接滑动到2001,后者的ACK=2001就包含了ACK=1001所表示的含义。
数据报丢失
- 当数据报丢失后,主机B就会连续发送请求该数据包的ACK,当主机A收到连续的三个ACK时,主机A就会重新发送一遍该数据报。
- 主机A在连续收到ACK=1001时,滑动窗口是不会进行滑动的。
- 主机B在连续发送ACK=1001时,到达的数据就会存储在缓冲区里面,当1001——2000数据到达的时候,主机B就知道7001之前的数据都到了,就继续索要7000以后的数据了。
5. 流量控制
5.1 流量控制的原理
流量控制就是:根据接受方的接收能力,来限制发送方滑动窗口的大小。
把B的TCP的接收缓冲区想象成一个水池
A就相当于水池的入水口
B读取数据就相当于出水口
5.2 流量控制的实现形式
在报文段中就有一个”窗口大小“的字段,接受方通过这个字段的反馈就可以知道接受方的接收能力了。
5.3 由TCP协议报文段分析滑动窗口大小
由上图可知,“TCP窗口大小” 为16位,16位表示的最大数是65535,那么TCP窗口最大就是65535字节吗?
其实并不是,因为TCP首部的40字节选项中,包含了一个窗口扩大因子M,实际窗口大小是 窗口字段值左移M位。
6. 拥塞控制
6.1 产生拥塞的原因
在数据传输的过程中,除了有发送方和接收方以外,还有许多的网络设备:
这些设备的数据传输能力参差不齐,所以发送方在传输数据时,如果不考虑这些设备的传输能力,就容易造成网络环境的拥塞。
6.2 拥塞控制
MSS:数据报
cwnd:拥塞窗口
7. 延时应答
让窗口在保证可靠性的基础上,尽量更大一点,从而提高效率。
下面,我们用一个例子展示以下下延时应答的优点:
对比一下就能知道:延时应答时,送货方第二次运输来的货物就比立即应答更多一点,这就相当于是增大了发送端的cwnd。
采用延时应答就会延时上面的这种好处,从而提高了数据传输的效率。
8. 捎带应答
有了延时应答的机制,那么就可以使ACK延时,和响应一起返回,从而省去了一次封装分用的时间,从而提高了效率。
注意:捎带应答是一个概率性的机制,并不会100%发生。
9. 面向字节流——粘包问题
9.1 粘包问题(TCP传输)
9.2 如何解决粘包问题?
想要解决粘包问题,就得设计一个合理的应用层协议来解决。方法如下:
-
给应用层数据设定“结束符”,“分隔符”;
-
给应用层数据设定长度。
10. 异常情况
10.1 进程终止
假设数据传输的双方中,有一方的的进程意外终止,这个过程是可以被操作系统察觉到的,操作系统就会代替该进程,向另一方发送FIN报文给对方,然后与对方进行“四次挥手”。
10.2 机器重启
机器重启的时候,也是先关掉进程,所以可进程终止一样,但是有可能操作系统在发送FIN的时候,也会关闭,所以这个四次握手会进行,但是不一定能完成。
10.3 机器掉电、网线断开
- 接收方掉电:此时发送方发送完数据之后,就不会接受到接受方返回的ACK,于是就会超时重发,重发几次之后,就会尝试重置连接,再然后 发送方就会放弃这个连接,把连接对应的资源也就回收了。
- 发送方掉电:此时的接受方无法知道发送方是挂了,还是暂时没有发送数据,所以此时就采用一个机制,叫做”心跳包“,也叫做”保活“。
心跳包
每隔一段时间,向对方发送一个PING包,期待对方回复一个PONG包,如果PING包发过去之后,对方没有回复PONG包,并且多试几次之后也不行,此时就说明对方挂了。
【面试题目】
如何基于UDP协议实现可靠传输?
这个问题,看似文UDP,其实考的就是TCP。
- 实现确认应答机制。
- 实现序号、确认序号,以及去重
- 实现超时重复
- 实现连接管理
- 实现滑动窗口
- 为了提高滑动窗口的可靠性,实现流量控制,拥塞控制。
- 实现延时应答,捎带应答,心跳机制。
UDP 和 TCP的适用场景
- 如果需要确保可靠性,就用TCP
- 如果传输的单个数据报的长度比较长(超过64k),就用TCP
- 如果特别注重效率,就用UDP
- 如果需要进行广播,就用UDP
注意:传输层协议不知这两种