TCP大并发短连接造成TIME_WAIT问题解决办法

这两天用python写了一个TCP的短连接压力测试脚本,模拟100路并发不间断的访问。脚本运行几分钟后开始全面报错,错误代码为10048或者99,使用netstat命令查看网络发现大量的连接处于TIME_WAIT状态。

仔细阅读了《unix网络编程》相关章节,弄清楚了问题发生的原因,并找到了解决办法。

问题原因:

TCP连接的Close默认行为是将socket标记为关闭然后立即返回。此时socket描述符不能继续被进程使用:作为read和write的参数。但是socket依然向对端发生已经缓存在队列中的数据,当所有数据都发生完毕后,socket进入TCP的四次包交换关闭时序。主动调用Close的一端在收到对端发来的FIN之后进入TIME_WAIT状态,并持续2MSL的时间。MSL在不同的TCP的实现中是不同的,一般是30秒到2分钟之间,所以2MSL为1~4分钟。socket再进入closed状态之前端口是一直被占用的,因此在TCP短连接大规模并发时很快便耗尽了可用的端口,因此就出现了10048或者99的错误。

解决办法:

通过SO_LINGER Socket选项改变Close的行为。

首先来了解下SO_LINGER socket选项:

该选项决定socket的close行为,默认情况下,close立即返回,但是如果socket的发送缓冲区中仍然有数据时,系统将继续会发送这些数据到对端。

SO_LINGER socket选项让我们可以改变close的默认行为。该选项要求如下数据结构传递到内核,它的定义在<sys/socket.h>中。

struct linger 
{
    int   l_onoff; /* 0==off, nonzero=on*/
    int   l_linger; /* linger time, POSIX specifies units as seconds */
};
根据l_onoff和l_linger的不同的取值,有如下三种场景:

1. 如果l_onoff等于0,该选项关闭,l_linger的值忽略,close为默认行为。

2. 如果l_onoff非0时,l_linger也等于0,当调用close时,TCP立即断开连接。详细过程是TCP丢弃所有仍然留在发送缓冲区的数据,向对端发送一个RST, 不进入普通的四次包交换时序。该设置socket避免了CLOSE_WAIT状态。

3. 如果l_onoff非0,l_linger大于0,当socket被close时,系统内核将延迟。即,当socket的发送缓冲区中任然有未发送的数据时,进程进入睡眠直到以下几种情况发生:

i)所有的数据已经发送且收到TCP对端发来的ack, 或者ii) linger超时。


从上述的三种场景来看,很明显2符合避免CLOSE_WAIT状态的要求,是解决该问题的关键。python的实现代码如下:

optval = struct.pack("ii",1,0)
tcp_client.setsockopt(SOL_SOCKET, SO_LINGER, optval )



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值