Bootstrap

【Linux | 计网】TCP协议详解:从定义到连接管理机制

目录

1.TCP协议的定义:

2.TCP 协议段格式

3.TCP两种通信方式

4.确认应答(ACK)机制

解决“后发先至”问题

5.超时重传机制

那么, 超时的时间如何确定?

6.连接管理机制:

6.1.三次握手:

为什么需要3次握手,一次两次不行吗?

小结:

三次握手有以下优点:

6.2.四次挥手

为什么连接的时候是三次握手,关闭的时候却是四次握手?挥手的时候可以将ACK和FIN一起发送吗

1.TCP协议的定义:

TCP 全称为 "传输控制协议(Transmission Control Protocol"). 人如其名, 要对数据的传输进行一个详细的控制;

2.TCP 协议段格式

2.1.各个部分的含义:

  • 源/目的端口号: 表示数据是从哪个进程来, 到哪个进程去;
  • 32 位序号/32 位确认序号 = 序号 + 1
  • 4 位 TCP 报头长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个 4 字节); 所以TCP 头部最大长度是 15 * 4 = 60
  • 6 位标志位:
  1. URG: 紧急指针是否有效
  2. ACK: 确认号是否有效
  3. PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
  4. RST: 对方要求重新建立连接; 我们把携带 RST 标识的称为复位报文段
  5. SYN: 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
  6. FIN: 通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段
  • 16 位窗口大小: 后面再说
  • 16 位校验和: 发送端填充, CRC 校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含 TCP 首部, 也包含 TCP 数据部分.
  • 16 位紧急指针: 标识哪部分数据是紧急数据;
  • 40 字节头部选项: 暂时忽略;

3.TCP两种通信方式

  1. 客户端每次发送数据,都会立刻接收到应答
  2. 客户端发送多个数据时,一次性返回多个应答

很明显方案二更加高效,但是方案二有一个缺陷,那就是如果多个应答中有一个应答丢失,如何知道是哪一个应答丢失呢?所以这就需要确认应答机制中的序列号和确认序号出马了!

4.确认应答(ACK)机制

什么是确认应答机制?
我们平时交流的时候,怎么确认对方接受到了我们传送的消息呢?就需要对方给我们传递一个应答消息表示对方已经接受到了我们的消息

基本原理:
TCP确认应答机制的核心思想是,发送方在发送数据后,接收方需要向发送方返回一个确认应答报文(ACK报文),以告知发送方数据已成功接收。这一机制确保了发送方能够知道其发送的数据是否已被接收方正确接收。

确认应答机制的特性:

  • 收到了应答就知道历史数据100%被对方收到了!这就是可靠性!
  • 如果应答没有成功传给对方呢?客户端就会认为数报文丢失了,就会重新再发送一次报文(超时重传机制)。

解决“后发先至”问题

在网络传输过程中,由于路径延迟和节点繁忙程度的不同,可能会出现“后发先至”的问题,即后发送的数据包先到达接收方。为了解决这个问题,TCP引入了序号和确认序号的概念,通过对数据进行编号,接收方可以准确地识别出每个数据包的顺序,并生成正确的确认序号。

TCP 将每个字节的数据都进行了编号. 即为序列号。

  • 发送序号(seq):用于标识发送方发送的每个数据包的起始字节序号。这样,接收方可以根据序号来重组乱序到达的数据包,确保数据的正确顺序和完整性。
  • 确认序号(ack):用于标识接收方期望从发送方接收到的下一个数据包的起始字节序号。它实质上是接收方告诉发送方:“我已经成功接收到了哪个序号之前的所有数据,请从这个序号开始发送后续的数据。”通过这一机制,发送方可以确认其发送的数据是否已被接收方正确接收,并据此决定是否需要重传某些数据包。

确认序号 = 收到的序号 + 1,表示该确认序号之前的数据,我们已经全部收到,下次发送请从确认序号开始!

比如1000,2000 , 4000 的数据到了,但是3000的没到,那么就先将1000, 2000的传给上层,等待3000再将4000一切交给上层。

这就保证了确认序号前的全部数据,我们都已经全部收到!

5.超时重传机制

  • 主机 A 发送数据给 B 之后, 可能因为网络拥堵等原因, 数据无法到达主机 B;
  • 如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答, 就会进行重发;

超时重传会对发送的报文,并且没有收到应答的报文进行保存(在滑动窗口当中),方便我们进行重传!

但是, 主机 A 未收到 B 发来的确认应答, 也可能是因为 ACK 丢失了,如下图:

因此主机 B 会收到很多重复数据. 那么 TCP 协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.
这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.

那么, 超时的时间如何确定?

  • 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".
  • 但是这个时间的长短, 随着网络环境的不同, 是有差异的.
  • 如果超时时间设的太长, 会影响整体的重传效率;
  • 如果超时时间设的太短, 有可能会频繁发送重复的包;

TCP 为了保证无论在任何环境下都能比较高性能的通信, 因此会根据网络环境动态计算这个最大超时时间.

  • Linux 中(BSD Unix 和 Windows 也是如此), 超时以 500ms 为一个单位进行控制, 每次判定超时重发的超时时间都是 500ms 的整数倍.
  • 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
  • 如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
  • 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接

6.连接管理机制:

6.1.三次握手:

  1. 第一次握手:客户端向服务器发送一个带有SYN(Synchronize Sequence Numbers,同步序列号)标志位的TCP数据包,请求建立连接。这个数据包中包含了客户端的初始序列号(ISN,Initial Sequence Number)。
  2. 第二次握手:服务器收到客户端的SYN请求后,会回复一个带有SYN和ACK(Acknowledgment,确认)标志位的数据包,称为SYN-ACK响应。这个响应中,服务器确认了客户端的SYN请求,并指定了服务器的初始序列号(ISN)。同时,服务器还会对客户端的初始序列号进行确认,即发送一个确认号(ACK号),表示已经收到客户端发送的序列号加1的数据。
  3. 第三次握手:客户端收到服务器的SYN-ACK响应后,会发送一个带有ACK标志位的数据包,表示确认了服务器的响应。这个ACK数据包中,客户端会确认收到了服务器的SYN响应,并指定了下一个要发送的序列号(即服务器的初始序列号加1)。至此,三次握手完成,TCP连接建立成功,双方可以开始进行数据传输

举个生活中的例子:

小帅想跟小美谈恋爱,小帅先对小美说:我喜欢你,我们在一起谈恋爱吧!这就是第一次握手。

小美接受到小帅的表白后,也相中了小帅,回应道:我也喜欢你,那我们什么时候开始呢?小美的应答就是第二次握手。

小帅说:就现在!这就是第三次握手,成功搭建通信流程!

为什么需要3次握手,一次两次不行吗?

一次握手就能成功的话,也就代表着不需要进行确认,那么万一有恶意的服务器一直发送SYN,而服务器需要维护大量的连接,维护连接又需要成本,那么就很容易引发SYN洪水,导致服务器崩溃二次握手也是一样的道理。

SYN洪水攻击对目标服务器的影响是巨大的。由于服务器资源被大量无效的SYN请求占用,合法的用户请求会被拒绝或延迟处理。这可能导致服务器无法提供正常的服务,甚至造成整个网络的瘫痪。

小结:

三次握手的关键是要确认对方收到了自己的数据报。这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,Ack = Seq + 1成立,就代表对方正确收到了自己的数据包。

3次握手完成的主要功能就是要确保双方做好发送数据的准备工作(双方都知道彼此已准备好)

三次握手有以下优点:

  1. 验证全双工:三次握手可以验证网络的连通性,因为三次回收中客户端和服务端都进行了收发数据!
  2. 确认双方意愿:三次握手可以保证双方都想要建立连接!可以达成一个共识!
  3. 成本低:四次握手和五次握手等不过也是为了完成前两个目的!而三次握手是成本最低的!

6.2.四次挥手

当数据传输完成后,TCP连接需要释放。连接释放的过程需要客户端和服务器之间通过四次交互来确认连接已经关闭,这四次交互被称为四次挥手。

  • 第一次挥手:Clien发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  • 第二次挥手:Server收到FIN后,发送一个ACK给Client,Server进入CLOSE_WAIT状态。
  • 第三次挥手: Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,发送ACK给Server,Server进入CLOSED状态,完成四次握手。

为什么连接的时候是三次握手,关闭的时候却是四次握手?挥手的时候可以将ACK和FIN一起发送吗

在三次握手的时候,可以直接将SYN和ACK进行合并发送,

但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。

只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

客户端想要断开连接发送FIN,服务器收到之后发送ACK应答,但是服务器在大多数情况下是不会立刻断开连接,因为可能还有业务没有处理完所以ACK和FIN之间一定有一个时间差,这就导致了ACK不能和FIN一起发送。

TCP的三次握手一定能保证传输可靠吗?

不能!

三次握手比两次更可靠,但也不是完全可靠,而追加更多次握手也不能使连接更可靠了。因此选择了三次握手。

;