TCP的TIME_WAIT状态分析

2 篇文章 0 订阅

1.TCP状态

CLOSED:无连接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个连接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个连接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另一边已同意释放
ITMED_WAIT:等待所有分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另一边已初始化一个释放
LAST_ACK:等待最后一个ACK信号,就关闭

2.发生的场景

在四次挥手的过程中,发起连接的一方会有一段时间处于TIME_WAIT的状态。需要注意的是,只有发起连接终止的一方会进入 TIME_WAIT 状态。

关闭一个连接需要从两个方向上分别进行关闭,双方都是通过发送来表示单方向数据的关闭。

TCP 连接终止时,主机 1 先发送 FIN 报文,主机 2 进入 CLOSE_WAIT 状态,并发送一个 ACK 应答,同时,主机 2 通过 read 调用获得 EOF,并将此结果通知应用程序进行主动关闭操作,发送 FIN 报文。主机 1 在接收到 FIN 报文后发送 ACK 应答,此时主机 1 进入 TIME_WAIT 状态。

主机 1 在 TIME_WAIT 停留持续时间是固定的,是最长分节生命期 MSL(maximum segment lifetime)的两倍,一般称之为 2MSL。和大多数 BSD 派生的系统一样,Linux 系统里有一个硬编码的字段,名称为TCP_TIMEWAIT_LEN,其值为 60 秒。也就是说,Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。

3.TIME_WAIT的作用

主要是让TCP报文得以自然消失,为了确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。

4.TIME_WATI的危害

1) 是内存资源占用,这个目前看来不是太严重,基本可以忽略。

2) 是对端口资源的占用,一个 TCP 连接至少消耗一个本地端口。端口资源也是有限的,一般可以开启的端口为 32768~61000 ,也可以通过net.ipv4.ip_local_port_range指定,如果 TIME_WAIT 状态过多,会导致无法创建新连接。

 

5.优化TIME_WAIT

1) 改变系统的TIME_WAIT最大连接数(net.ipv4.tcp_max_tw_buckets)

通过sysctl命令将系统值调小,默认是18000,当系统处于time_wait的连接数一旦超过该值时,系统就会将所有的TIME_WAIT连接状态重置,并且只打印出警告信息。这个方法过于暴力,而且治标不治本,带来的问题远比解决的问题多,不推荐使用。

2) 调低TCP_TIMEWAIT_LEN

减小MSL的时间(Max segment lifetime),需要重新编译内核,麻烦!

3) SO_LINGER属性设置

通过设置套接字的属性来close或shutdown关闭连接的行为。


int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

struct linger {
 int  l_onoff;    /* 0=off, nonzero=on */
 int  l_linger;    /* linger time, POSIX specifies units as seconds */
}

linger参数说明

  • l_onoff=0, 关闭选项,忽略l_linger的值,对应的是默认行为,close 或 shutdown 立即返回。如果在套接字发送缓冲区中有数据残留,系统会将试着把这些数据发送出去。
  • l_onoff != 0 && l_linger=0,那么调用 close 后,会立该发送一个 RST 标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了 TIME_WAIT 状态,直接关闭。这种关闭的方式称为“强行关闭”。 在这种情况下,排队数据不会被发送,被动关闭方也不知道对端已经彻底断开。只有当被动关闭方正阻塞在recv()调用上时,接受到 RST 时,会立刻得到一个“connet reset by peer”的异常。为跨越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));
  • 如果l_onoff为非 0, 且l_linger的值也非 0,那么调用 close 后,调用 close 的线程就将阻塞,直到数据被发送出去,或者设置的l_linger计时时间到。

 

4) net.ipv4.tcp_tw_reuse(更加安全的设置)

从协议角度理解如果是安全可控的,可以复用处于TIME_WAIT的套接字为新连接的套接字可用。

什么叫安全可控呢?

  • 只适用于连接发起方(客户端)
  • 对应的TIME_WAIT状态的连接创建时间超过1s才可以被复用(这就需要打开TCP的时间戳支持,即net.ipv4.tcp_timestamp=1)

6.系统内核的TCP参数

  • 完整的参数信息
# man 7 tcp
  • 通过指令查看
# sysctl -a
  • 查看文件信息
# ls /proc/sys/net/ipv4
  • 命令查看TIME_WAIT连接数
# netstat -ae|grep "TIME_WAIT" |wc -l
  • 调整内核参数
# vim /etc/sysctl.conf

编辑文件,加入以下内容:


#该方法还未测试验证过,慎用!

#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭
net.ipv4.tcp_syncookies = 1  
#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
net.ipv4.tcp_tw_reuse = 1
#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭
net.ipv4.tcp_tw_recycle = 1
#修改系統默认的TIMEOUT时间
net.ipv4.tcp_fin_timeout = 30

然后执行/sbin/sysctl -p让参数生效

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值