TCP特性
- 拥塞控制(可靠性机制)
- 延迟应答(效率机制)
- 捎带应答(效率机制)
- 面向字节流(粘包问题)
- TCP异常机制(心跳包)
- 小结
拥塞控制(可靠性机制)
虽然TCP引入了滑动窗口,能够高效可靠的传输大量数据,但是在开始阶段就发送大量数据,可能引起一系列问题.
TCP引入了慢启动机制,先发少量的数据,判断当前的网络拥堵状态后,再决定按照多大的速度传输数据.
“拥塞窗口”: 在拥塞控制机制下,采用的窗口大小.
- 慢启动: 刚开始进行通信时,会使用非常小的窗口,探探路.
- 指数增长: 在传输通畅的条件下,拥塞窗口会指数型增长.
- 线性增长: 当指数增长到一个阈值后,就会从指数增长转变为线性增长.
- 拥塞窗口回归小窗口: 在窗口增大的过程中,如果传输出现丢包,认为当前网络出现拥堵了,
此时就会把窗口大小调整为最初的小窗口,继续进行指数增长->线性增长的过程,会根据刚才
丢包的窗口大小,调整阈值.
当出现网络拥堵(丢包)后,把丢包窗口大小 / 2变为新的阈值,拥塞窗口就是在这个过程不断发生变化,
在权衡之下,我们实际发送的窗口大小为 = min(拥塞窗口, 流量控制窗口).
拥塞控制和流量控制共同限制了滑动窗口机制,可以使滑动窗口在保证可靠性的前提下,提升效率了.
延迟应答(效率机制)
我们是否有办法在条件允许的基础上,尽可能的提高窗口大小呢?
延迟应答就向我们挥手了, 可以在接收方返回ACK的事后,拖延一下,利用拖延的时间尽可能的消费接收缓冲区的数据,这样接收缓冲区剩下的空间就会更大了.
通过延迟应答的方式,提高的速度取决于接收方实际的处理数据的能力,如果在拖延的时间里你还是没有处理更多数据,那么延迟应答带来的提升就会很小.
也不是所有的包都会出发延迟应答:
- 滑动窗口(数量限制): 每隔N个包就应答一次.
- 非滑动窗口(时间限制): 超过最大延迟时间就应答一次.
捎带应答(效率机制)
在延迟应答的基础上,引入了进一步提升效率的方式.
延迟应答: 让ACK传输的更慢.
捎带应答: 基于延迟应答,使数据合并
这是没有捎带应答的方式:
这是带有捎带应答的方式:
加入捎带应答后,两条效用合并了,这也是四次挥手也可能是三次的原因,主要是捎带应答和延迟应答起到的效果.
面向字节流(粘包问题)
这里用一个经典问题(“粘包问题”).包: 应用层数据报
发送方可以一次性发送很多应用层数据报,但是在接收的时候,如何区分呢?
此时不是传输层的问题,而是站在应用层的角度解决这个问题:
- 应用层协议中,引入分隔符,区分包的边界.
接收方就可以按照\n区分应用层数据报的边界了.
- 应用层协议中,引入包长度,区分包的边界.
根据长度读取数据.
粘包问题不仅仅是TCP独有的,面向字节流机制的都用同样的问题,就可以引入分隔符和长度来解决.
xml / json是根据分隔符来区分的,protobuffer是根据长度来区分的.
TCP异常机制(心跳包)
- 进程崩溃:
进程结束 -> PCB没了 -> 文件描述符表释放了 == socket.close().
崩溃的一方会发出FIN -> 四次挥手 -> 连接正常释放了. - 主机关机:
正常关机后,会尝试终止所有进程,和进程崩溃时一样的处理结果.但是当接收方的FIN发过来是,请求方已经关机了,接收方收不到ACK就会重传FIN,连续尝试几次后都没有收到ACK,就单方面释放了. - 拔掉电源:
- 接收方正给发送方发消息:
接收方收不到ACK就会重传FIN,连续尝试几次后都没有收到ACK,就单方面释放了. - 发送方正给接收方发消息:
接收方在等待发送方的消息,至于等多久我们是不知道的,这里就涉及到心跳包.
虽然是接收方,长时间收不到数据,也会周期性的给发送方发一个不带任何业务的TCP数据报,就是为了确认发送方是否正常工作/确认网络是否畅通.
- 网线断开:
此时发送方和接收方就无法通信了,有两种情况
如果是发送方断了,就是拔掉电源的接收方正给发送方发消息的情况.
如果是接收方断了,就是拔掉电源的发送方正给接收方发消息的情况.
小结
结合前面几篇博客,一共总结了TCP特性中的10个.
- 确认应答(可靠性核心机制)
- 超时重传(可靠性机制)
- 三次握手和四次挥手(可靠性机制)
- 滑动窗口(效率机制)
- 流量控制(可靠性机制)
- 拥塞控制(可靠性机制)
- 延迟应答(效率机制)
- 捎带应答(效率机制)
- 面向字节流(粘包问题)
- TCP异常情况(心跳包)
希望有收获的小伙伴多多支持!