Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题( 六 )

  • M 是一个计时器 , 这个计时器每隔 4 毫秒加 1 。
  • F 是一个 Hash 算法 , 根据源 IP、目的 IP、源端口、目的端口生成一个随机数值 。 要保证 Hash 算法不能被外部轻易推算得出 , 用 MD5 算法是一个比较好的选择 。
  • 既然 IP 层会分片 , 为什么 TCP 层还需要 MSS 呢?
    我们先来认识下 MTU 和 MSS

    Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
    本文插图
    MTU 与 MSS
    • MTU:一个网络包的最大长度 , 以太网中一般为 1500 字节;
    • MSS:除去 IP 和 TCP 头部之后 , 一个网络包所能容纳的 TCP 数据的最大长度;
    如果TCP 的整个报文(头部 + 数据)交给 IP 层进行分片 , 会有什么异常呢?
    当 IP 层有一个超过 MTU 大小的数据(TCP 头部 + TCP 数据)要发送 , 那么 IP 层就要进行分片 , 把数据分片成若干片 , 保证每一个分片都小于 MTU 。 把一份 IP 数据报进行分片以后 , 由目标主机的 IP 层来进行重新组装后 , 在交给上一层 TCP 传输层 。
    这看起来井然有序 , 但这存在隐患的 , 那么当如果一个 IP 分片丢失 , 整个 IP 报文的所有分片都得重传 。
    因为 IP 层本身没有超时重传机制 , 它由传输层的 TCP 来负责超时和重传 。
    当接收方发现 TCP 报文(头部 + 数据)的某一片丢失后 , 则不会响应 ACK 给对方 , 那么发送方的 TCP 在超时后 , 就会重发「整个 TCP 报文(头部 + 数据)」 。
    因此 , 可以得知由 IP 层进行分片传输 , 是非常没有效率的 。
    所以 , 为了达到最佳的传输效能 TCP 协议在建立连接的时候通常要协商双方的 MSS 值 , 当 TCP 层发现数据超过 MSS 时 , 则就先会进行分片 , 当然由它形成的 IP 包的长度也就不会大于 MTU, 自然也就不用 IP 分片了 。

    Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
    本文插图
    握手阶段协商 MSS
    经过 TCP 层分片后 , 如果一个 TCP 分片丢失后 , 进行重发时也是以 MSS 为单位 , 而不用重传所有的分片 , 大大增加了重传的效率 。
    什么是 SYN 攻击?如何避免 SYN 攻击?
    SYN 攻击
    我们都知道 TCP 连接建立是需要三次握手 , 假设攻击者短时间伪造不同 IP 地址的 SYN 报文 , 服务端每接收到一个 SYN 报文 , 就进入SYN_RCVD 状态 , 但服务端发送出去的 ACK + SYN 报文 , 无法得到未知 IP 主机的 ACK 应答 , 久而久之就会占满服务端的 SYN 接收队列(未连接队列) , 使得服务器不能为正常用户服务 。
    Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
    本文插图
    SYN 攻击
    避免 SYN 攻击方式一
    其中一种解决方式是通过修改 Linux 内核参数 , 控制队列大小和当队列满时应做什么处理 。
    • 当网卡接收数据包的速度大于内核处理的速度时 , 会有一个队列保存这些数据包 。 控制该队列的最大值如下参数:
    net.core.netdev_max_backlog
    • SYN_RCVD 状态连接的最大个数:
    net.ipv4.tcp_max_syn_backlog
    • 超出处理能时 , 对新的 SYN 直接回 RST , 丢弃连接:
    net.ipv4.tcp_abort_on_overflow
    避免 SYN 攻击方式二
    我们先来看下Linux 内核的 SYN (未完成连接建立)队列与 Accpet (已完成连接建立)队列是如何工作的?
    Java:吊打面试官!近 40 张图解被问千百遍的 TCP 三次握手和四次挥手面试题
    本文插图


    推荐阅读