TCP的10种核心机制【未完】

TCP内部的工作机制

1. 确认应答

确认应答是实现可靠传输的最核心的机制。
可靠传输并不是说100%的就可以吧数据发送过去,而是尽可能的吧数据传输过去,如果传输不过,需要知道没有传输成功。
A给B发送了一个数据,B收到后,就会返回一个应答报文(ACK),A收到应答后,就知道刚才的数据已经顺利发送给B了。
而网络中很容易出现先发后至这一问题,因此应答报文的到达顺序会发生变动,此时就需要给传输的数据和应答报文,进行编号,就可以解决这一问题。TCP是面向字节流的,因此TCP的序号也是按照字节进行编号的。字节的序号是依次累加的。
任何一条数据(包括应答报文)都是有序号 。
确认序号则只有应答报文有。普通报文的确认序号字段值没有意义。

2. 超时重传

确认应答只是考虑了顺利传输的情况,如果丢包了,我们就要考虑怎么进行重传。
丢包涉及到两种情况:

  1. 发送的数据丢失了
  2. 返回的确认响应ACK丢失了。
    发送方无法判断是那种丢包,因此对这两种情况的处理是一样的 ---- 引入重传机制

重传机制:在丢包后,重新发送一次同样的数据。
但如何判断当前的这次传输,是丢包了,还是ack走的慢,还没有收到。
TCP引入了一个时间阈值,当发送方发了一个数据之后,就会等待ACK,此时开始计时,如果在时间阈值之内,没有收到ACK,不论此时ACK是在路上,还是已经丢失,都视为已经丢包。

如果由于重传,导致接收方收到了重复的消息,应该怎么处理呢?

TCP对于这种重复数据的传输,会进行特殊处理:去重。
TCP存在一个 “接收缓冲区” 这样的存储空间(接收方操作系统内核里的一段内存)
每个 TCP 的 socket 对象,都有一个接收缓冲区(也有一个发送缓冲区)
主机 B 收到的主机 A 的数据,其实是 B 的网卡读到数据了,然后把这个数据放到 B 的对应 socket 的接收缓冲区中。可以将这个接收缓冲区想像成一个阻塞队列(优先级队列 / 有序队列)。由于数据有可能后发先至,TCP使用这个接收缓冲区,对收到的数据进行重新排序,使应用程序read到的数据是保证有序的(和发送顺序一致)。
根据数据的序号, TCP很容易识别当前接收缓冲区里的这两条数据是否是重复的。
如果重复则把后来的这份数据就直接丢弃。这样就保证了应用程序调用read读取到的数据,一定是不重复的。
后续应用程序使用 getInputStream ,进一步的使用 read,从接收缓冲区来读数据。

可靠传输是TCP最核心的部分,TCP的可靠传输就是通过 确认应答+ 超时重传 体现的
确认应答描述的是传输顺利的情况;超时重传是传输出现问题的时候。两者相互配合,共同支撑起整体TCP的可靠性。

3. 连接管理

TCP的建立连接过程(三次握手)和断开连接过程(四次挥手)

所谓的三次握手,本质上是"四次"交互。通信双方各自要向对方发起一个“建立连接"的请求,同时, 再各自向对方回应一个ack,这里其实是一共有四次信息交互。
但中间两次交互,是可以合并成一次交互的。因此就构成了"三次握手"。

三次握手的重要作用:验证通信双方各自的发送能力和接收能力是否正常。

因为TCP是有连接的,所以TCP需要建立连接 / 断开连接。其中建立连接的流程是三次握手。

三次握手的意义:

  1. 让通信双方各自建立对对方的认同。
  2. 验证通信双方各自的发送能力和接收能力
  3. 在握手的过程中,双方来协商一些重要参数。(TCP通信过程中,有些数据通信双方要相互同步,此时就需要有这样的交互过程。恰好可以利用三次握手的机会完成数据的同步。)

在这里插入图片描述

在关闭窗口时,B收到fin就会立即返回ack(内核完成的),应用程序在合适的时机,调用close方法,才会触发B发送fin。

4. 滑动窗口机制

上述的确认应答、超时重传、连接管理,都是给TCP提供了可靠性的支持。
而引入可靠性,实际上付出的代价就是降低了传输效率。
滑动窗口机制,本质上就是降低了确认应答等待ack所消耗的时间。
在这里插入图片描述
如果出现丢包:

  1. ack丢了
    在使用窗口控制之后,某些确认应答即使丢失也不用重发。
    确认应答表示从该序号往前的所有数据都已经确认到达。
  2. 数据丢了
    如果发生某个报文段丢失的情况:接收主机如果收到一个不是自己应该接收的序号的数据,会针对当前收到的数据返回确认应答。
    在窗口较大,报文段丢失的情况下 ,同一个序号的确认应答将会被重复不断的返回。
    当发送端主机连续3次收到同一个确认应答,就会对其对应的数据进行重发,这种机制被称为高速重发机制。

5. 流量控制

流量控制是一种干预发送的窗口大小机制。

滑动窗口的窗口越大,传输效率就越高(一份时间,等的ack就越多)
但是,窗口也不能无限大

  1. 完全不等ack,可靠性能否保障。
  2. 窗口太大,消耗大量的系统资源。
  3. 发送速度太快,接收方处理不过来。

接收方的处理能力,就是窗口大小的重要的约束依据。发送方发的速度,不能超出接收方的处理能力。

流量控制做的就是:根据接收方的处理能力,协调发送方的发送速率。
如何衡量接收方发处理能力:接收方缓存区剩余的大小

6. 拥塞控制

流量控制和拥塞控制共同决定发送方的窗口大小。

流量控制考虑的是接收方的处理能力。
拥塞控制描述的是传输过程中,中间节点的处理能力。

拥塞控制本质上,是通过实验的方式,逐渐找到一个合适的窗口大小(合适的发送速率)

  1. 初始阶段,由于初始窗口较小,每一轮不丢包都会时窗口大小扩大一倍。(指数增长)
  2. 当增长速率达到阙值(初始ssthresh)之后,此时指数增长,就成为了线性增长。(增长的前提时不丢包)
  3. 当传输过程中一旦丢包了(网络拥塞),说明此时的发送速率接近网络极限,此时就把窗口大小一下子缩成很小的值,(拥塞时的窗口大小 / 2,就是新的ssthresh值 ),再次重复刚才的指数增长和线性增长。

拥塞窗口不是固定的数值,而是一直动态变化的,随着时间的推移,逐渐的达到一个动态平衡的过程。

7. 延时应答

延时应答也是提升效率的机制。
针对滑动窗口的基础改进。在接收方能够处理的了前提下,尽可能把窗口大小放大一点。

延时:收到数据之后,不是立即返回ACK,而是稍微等一会再返回。
在等待的时间里,接收方的应用程序就能够把接收缓冲区的数据消费一些,此时剩余的空间就大了。

实际上延时应答采取的方案,就是在滑动窗口下,ACK不再返回每一条数据,比如可以隔一条返回一个ACK。
剩余的空间大小变化是一个复杂的过程,既取决于发送方发发送,也取决于接收方的处理。

8. 捎带应答

提高效率的方式。

服务器客户端程序,最典型的模式,就是:一问一答

基于延时应答,更有可能成为相同时机合并。

9. 面向字节流

面向字节流,引入了一个麻烦事:粘包问题,包指应用层的数据包
TCP是面向字节流的,
在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中
在应用层的角度,看到的只是一串连续的字节数据。

应用程序read读取的时候,看到的只是一串连续的字节数据。读到哪里才算是一个完整的应用层数据报?这就引发了粘包问题。

如果避免粘包问题:明确两个包之间的边界

  1. 约定明确的分隔符
  2. 约定每个包的长度

10. 异常情况

传输过程中出现了不可抗力。

  1. 进程崩溃

  2. 主机关机(正常流程关机)
    内核会继续完成四次挥手,仍然是一个正常的断开流程

  3. 主机掉电(拔电源)

  4. 网线断开
    来不及挥手,

猜你喜欢

转载自blog.csdn.net/weixin_44431128/article/details/128981038