《网络编程实战》笔记 | 10 TIME-WAIT:隐藏在细节下的魔鬼

0 前言

最近在学习极客时间上的《网络编程实战》专栏,正好把之前学习过的计算机网络知识的学习再复习一遍。之前的学习都是从理论出发,看了计算机网络(第七版)这本经典教材,读了小林coding公众号上的图解计算机网络文章。虽然有很多收获,但是相关的编程能力,还有欠缺。希望这次能通过专栏中的一些练习作业能让自己有实战能力,不是只会背书谈理论。
因为专栏前9节都是基础知识,这里就不再总结输出,笔记主要用于查漏补缺,补充实战相关知识。

1 TIME_WAIT 发生的场景

TIME_WAIT 是发生在 TCP 四次挥手的最后阶段,如下如所示:

TIME_WAIT 需要维持 2MSL 的时间长度,其中 MSL(maximum segment lifetime) 是最长分节生命期。在 Linux 系统中,有硬编码字段 TCP_TIMEWAIT_LEN,其值为 60 秒,也就是Linux系统停留在 TIME_WAIT 的时间为固定的 60 秒。

注意:只有发起连接终止的一方会进入TIME_WAIT状态

2 TIME_WAIT 的作用

在学习《计算机网络》(第七版)时,书中就提到TIME_WAIT有两个作用。如下:

  1. 为了保证终止发起方 A 发送的最后一个 ACK 报文段到达 B。当 B 未收到最后一个 ACK 报文,B 会重传 FIN 报文,A 收到后发送 ACK 并重置TIME_WAIT。
  2. 为了防止“已失效的连接请求报文段”出现在本连接中。2MSL 的时间,足以让网络中属于该连接的报文都消失。
    注意:TIME_WAIT 时间从连接终止发起方 A 收到 FIN 后发送 ACK 开始计时

3 TIME_WAIT 的危害

过多 TIME_WAIT 的主要危害:

  1. 内存资源占用
  2. 对端口资源的占用,一个 TCP 连接至少消耗一个本地端口。
    对于 Linux 系统,可使用如下命令查看实际可用本地端口范围:
matt@ubuntu:~$ sudo sysctl -a|grep net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768    60999

可以配置 net.ipv4.ip_local_port_range 参数指定端口使用范围。

4 如何优化 TIME_WAIT?

当处于 TIME_WAIT 状态的连接过多,可以使用如下方法进行处理:

  1. 使用 sysctl 调整 net.ipv4.tcp_max_tw_buckets 参数。——暴力,指标不治本
    当处于 TIME_WAIT 状态的连接超过该参数,系统会将所有的 TIME_WAIT 的连接状态重置,并只会打印警告信息。
  2. 调低 TCP_TIMEWAIT_LEN,重新编译内核。——需要内核相关知识,能够重编内核
  3. SO_LINGER 的设置——非常危险,不值得提倡
    如下代码设置后,close调用后,会立即发送一个RST 标志给对端,跳过四次挥手,不会有个 TIME_WAIT。
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
  1. net.ipv4.tcp_tw_reuse:更安全的设置
    该选项配置,从协议角度理解如果是安全可控的,可以复用处于 TIME_WAIT 的套接字为新的连接使用。
    安全可用:
    1)只适用于连接发起方
    2)对应的 TIME_WAIT 状态的连接创建时间超过 1 秒才可被复用
    依赖:
    net.ipv4.tcp_timestamps = 1(默认即为1)

RFC1323中实现了TCP拓展规范,引入了新的TCP选项,两个4字节的时间戳字段。这就避免了2MSL的问题。重复数据包,会因为时间戳过期被自然丢弃。

原文地址:https://www.cnblogs.com/1million/p/14329557.html