# TCP 的首部

  • 源端口:表示发送方的端口号
  • 目的端口:表示接收方的端口号
  • 序号:发送方一次 TCP 通信中每个字节的编号
  • 确认号:对发送方发送的 TCP 报文段的确认
  • 头部长度:表示 TCP 头部的长度,单位是 4 字节,最多为 15 个 4 字节 = 60 字节
  • 窗口大小:TCP 流量控制的手段,表示缓冲区的大小。
  • 校验和:校验数据的完整性。
  • 紧急指针:紧急指针相对当前序号的偏移,也可以叫做紧急偏移。

# TCP 如何保证可靠的

  • 三次握手、四次挥手确保连接的可靠性。
  • TCP 是有状态的。会记录哪些数据发送、哪些被接受,保证数据包按序到达。
  • TCP 是可控制的。有校验和、ACK 确认、重传机制、流量控制、拥塞控制。

# TCP 三次握手、四次挥手

略过~~

# 半连接队列和 SYN Flood 攻击的关系

  • TCP 进入三次握手前,会在内部创建两个队列:半连接队列(SYN 队列)和全连接队列(ACCEPT 队列)。
  • TCP 三次握手时,客户端发送 SYN 到服务端,服务端收到之后,便回复 ACK 和 SYN,状态由 LISTEN 变为 SYN_RCVD,此时这个连接就被推入了 SYN 队列,即半连接队列。
  • 当客户端回复 ACK, 服务端接收后,三次握手就完成了。这时连接会等待被具体的应用取走,在被取走之前,它被推入 ACCEPT 队列,即全连接队列。

SYN Flood 是一种典型的 DoS 攻击,它伪造大量不存在的 IP 地址,向服务器发起 SYN 报文。当服务器回复 SYN+ACK 报文后,并不会收到 ACK 回应报文,导致服务器上建立大量的半连接导致其队列爆满。

主要有 SYN cookie 和 SYN Proxy 防火墙等方案应对。

  • SYN cookie:在收到 SYN 包后,服务器根据一定的方法,以数据包的信息为参数计算出一个 cookie 值作为自己的 SYN + ACK 包的序列号,回复后服务器并不立即分配资源,等收到发送方的 ACK 包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包。

  • SYN Proxy 防火墙:服务器建立一个防火墙,防火墙对收到的每一个 SYN 报文进行代理和回应,并保持半连接。等发送方将 ACK 包返回后,再重新构造 SYN 包发到服务器,建立真正的 TCP 连接。

上面两种做法的建立在,攻击者通常使用的是伪造的 IP 地址,无法发送 ACK 确认包。

# TCP 重传机制

# 超时重传

当发送方发送一个数据包后,会开启一个定时器,等待接收方的 ACK 确认。如果在 2 个 RTT 内没有收到 ACK 确认,就会重新发送这个数据包。

# 快速重传

跟超时重传的区别是,它以数据驱动而不是网络。
接收端遵循一个 TCP 原则:只接收连续的数据包。举个例子:
当发送端发送了 seq = 1、2、3 数据包,接收端收到了 1、2 数据包,它的 ACK 依次为 2、3。因为网络原因数据包 3 丢失了,即使发送端持续发送 seq = 4、5、6 数据包,接收端都只会返回 ACK =3。
基于这个特性,发送端如果发现 ACK 没有连续增长,就会认为网络出了问题,会重新发送丢失的数据包 3。

# 带选择确认的重传

上面的快速重传有一个缺点,发送端只能知道自己发送失败的最大有序号 3,如果数据包 seq = 4、5、6 实际发送成功了,它可以不用重传。所以 TCP 提供了 SACK 机制,接收端在首部标记收到了哪些范围的数据包。这样就可以做到只重传丢失的数据包。

# TCP 流量控制

TCP 流量控制是指接收方控制发送方发送数据的速率,避免接收方缓冲区溢出。
接收方会在 ACK 中携带自己的窗口大小,发送方会根据这个窗口大小来控制发送的数据量。
如果接收方的缓冲区满了,就会将窗口大小设置为 0,发送方就会停止发送数据。并且轮询接收方直到窗口大小不为 0,再继续发送数据。

这个滑动窗口的大小是同时受拥塞窗口(cwnd)和接收窗口(rwnd)的最小值决定的。

# TCP 拥塞控制

拥塞控制是基于网络情况的,控制发送方发送数据的速率,避免网络拥塞。
拥塞控制有四种算法:慢开始、拥塞避免、快重传、快恢复。

# 慢启动算法

发送方会将窗口大小设置为 1,然后每收到一次 ACK,拥塞窗口 cwnd 大小会翻倍(指数增长)。当到达 ssthresh 阈值或出现丢包时结束此阶段。

# 拥塞避免算法

当到达慢启动阈值时,转为线性增长,拥塞窗口 cwnd 大小每次增加 1 个 MSS。

# 拥塞发生

当网络拥塞而产生丢包时,会产生两种重传:

  • 超时重传:会将 ssthresh 阈值设置为 cwnd/2,cwnd 大小设为 1,重新进入慢启动阶段,一夜回到解放前~~。
  • 快速重传:会将 ssthresh 阈值设置为 cwnd/2,cwnd 大小设为 ssthresh,进入快速恢复阶段。

# 快速恢复算法

正如前面所说,进入快速恢复之前,cwnd 和 sshthresh 已被更新:

  • cwnd = cwnd /2
  • sshthresh = cwnd

然后,真正的快速算法如下:

  • cwnd = sshthresh + 3
  • 重传重复的那几个 ACK(即丢失的那几个数据包)
  • 如果再收到重复的 ACK,那么 cwnd = cwnd +1
  • 如果收到新数据的 ACK 后,cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了。

# TCP 的粘包和拆包

TCP 是面向字节流的协议,它不了解业务数据的含义。所以可能会将一个业务数据包拆分成多个 TCP 数据包发送,也可能将多个 TCP 数据包合并成一个业务数据包发送。
这就是 TCP 的粘包和拆包问题。解决方法如下:

  • 定长协议:每个数据包的长度固定,接收方按照固定长度接收数据。
  • 分隔符协议:每个数据包之间使用特殊的分隔符进行分割,接收方按照分隔符进行分割。
  • 长度前缀:每个数据包都包含一个包头,包头中包含数据包的长度信息,接收方按照包头中的长度信息接收数据,类比 HTTP 的 content-length。

# Nagle 算法与延迟确认

如果发送方每次发送 1 字节的数据包,会导致可能会产生大量的网络流量,影响网络性能。
Nagle 算法就是为了解决这个问题,它会将多个小的数据包合并成一个大的数据包发送,从而减少网络流量,可以理解为延迟发送。
延迟确认是指发送方在发送数据包后,不会立即发送 ACK 确认,而是等待一段时间后再发送 ACK 确认。这样可以减少网络流量,提高网络性能。


参考文章:
TCP 协议经典十五连问 - 稀土掘金

更新于

请我喝[茶]~( ̄▽ ̄)~*

imtangx 微信支付

微信支付

imtangx 支付宝

支付宝

imtangx 贝宝

贝宝