• 网络编程:优雅关闭socket/TIME_WAIT/CLOSE_WAIT/SoLinger


    一个很特别的参数,影响关闭socket后的行为,是立即释放,还是进入TIME_WAIT状态并等 待一段时间(单位:秒)才释放。这个参数,在Socket中可以设置,在Mina2的IoService中也有setSoLinger设置。对于新bs3 框架的Service4Mina2s组件,可以通过以下两种方法设置。 
    <prop key="m_solinger">1</prop><!-- ={-1 | 0 | nSec}--> 
    <property name="soLinger"><value>1</value></property><!--仅仅针对服务器 ={-1 | 0 | nSec}--> 
    取值:-1表示使用OS缺省参数,0表示立即释放,nSec表示等待n秒后释放。 

    优雅关闭的几个步骤:1)shutdown(SEND);2)recv(EOF, 5s);3) closeSocket();4) TIME_WAIT 

    参考:http://hi.baidu.com/xingfengsoft/blog/item/021b03ce872e0430b700c89d.html 
    【转自文静】减少Linux服务器过多的TIME_WAIT (2009/08/24 22:45) 
    TIME_WAIT状态的意义: 
    客户端与服务器端建立TCP/IP连接后关闭SOCKET后,服务器端连接的端口状态为TIME_WAIT 
    是不是所有执行主动关闭的socket都会进入TIME_WAIT状态呢? 
    有没有什么情况使主动关闭的socket直接进入CLOSED状态呢? 
    主动关闭的一方在发送最后一个 ack 后,就会进入 TIME_WAIT 状态 停留2MSL(max segment lifetime)时间,这个是TCP/IP必不可少的,也就是“解决”不了的。 
    也就是TCP/IP设计者本来是这么设计的 
    主要有两个原因 
    1。防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失) 
    2。可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发 
    fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。 
    TIME_WAIT 并不会占用很大资源的,除非受到攻击。 
    在Squid服务器中可输入如下命令: 
    #netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 
    LAST_ACK 14 
    SYN_RECV 348 
    ESTABLISHED 70 
    FIN_WAIT1 229 
    FIN_WAIT2 30 
    CLOSING 33 
    TIME_WAIT 18122 
    状态:描述 
    CLOSED:无连接是活动的或正在进行 
    LISTEN:服务器在等待进入呼叫 
    SYN_RECV:一个连接请求已经到达,等待确认 
    SYN_SENT:应用已经开始,打开一个连接 
    ESTABLISHED:正常数据传输状态 
    FIN_WAIT1:应用说它已经完成 
    FIN_WAIT2:另一边已同意释放 
    ITMED_WAIT:等待所有分组死掉 
    CLOSING:两边同时尝试关闭 
    TIME_WAIT:另一边已初始化一个释放 
    LAST_ACK:等待所有分组死掉 
    也就是说,这条命令可以把当前系统的网络连接状态分类汇总。 
    下面解释一下为啥要这样写: 
    一个简单的管道符连接了netstat和awk命令。 
    —————————————————————— 
    先来看看netstat: 
    netstat -n 
    Active Internet connections (w/o servers) 
    Proto Recv-Q Send-Q Local Address Foreign Address State 
    tcp 0 0 123.123.123.123:80 234.234.234.234:12345 TIME_WAIT 
    你实际执行这条命令的时候,可能会得到成千上万条类似上面的记录,不过我们就拿其中的一条就足够了。 
    —————————————————————— 
    再来看看awk: 
    /^tcp/ 
    滤出tcp开头的记录,屏蔽udp, socket等无关记录。 
    state[] 
    相当于定义了一个名叫state的数组 
    NF 
    表示记录的字段数,如上所示的记录,NF等于6 
    $NF 
    表示某个字段的值,如上所示的记录,$NF也就是$6,表示第6个字段的值,也就是TIME_WAIT 
    state[$NF] 
    表示数组元素的值,如上所示的记录,就是state[TIME_WAIT]状态的连接数 
    ++state[$NF] 
    表示把某个数加一,如上所示的记录,就是把state[TIME_WAIT]状态的连接数加一 
    END 
    表示在最后阶段要执行的命令 
    for(key in state) 
    遍历数组 
    print key,”/t”,state[key] 
    打印数组的键和值,中间用/t制表符分割,美化一下。 
    如发现系统存在大量TIME_WAIT状态的连接,通过调整内核参数解决, 
    vim /etc/sysctl.conf 
    编辑文件,加入以下内容: 
    net.ipv4.tcp_syncookies = 1 
    net.ipv4.tcp_tw_reuse = 1 
    net.ipv4.tcp_tw_recycle = 1 
    net.ipv4.tcp_fin_timeout = 30 
    然后执行 /sbin/sysctl -p 让参数生效。 
    Linux下高并发的Squid服务器,TCP TIME_WAIT套接字数量经常达到两、三万,服务器很容易被拖死。通过修改Linux内核参数,可以减少Squid服务器的TIME_WAIT套接字数量。 
    vi /etc/sysctl.conf 
    增加以下几行:引用 
    net.ipv4.tcp_fin_timeout = 30 
    net.ipv4.tcp_keepalive_time = 1200 
    net.ipv4.tcp_syncookies = 1 
    net.ipv4.tcp_tw_reuse = 1 
    net.ipv4.tcp_tw_recycle = 1 
    net.ipv4.ip_local_port_range = 1024 65000 
    net.ipv4.tcp_max_syn_backlog = 8192 
    net.ipv4.tcp_max_tw_buckets = 5000 
    说明: 
    net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭; 
    net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; 
    net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 
    net.ipv4.tcp_fin_timeout = 30 表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间。 
    net.ipv4.tcp_keepalive_time = 1200 表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。 
    net.ipv4.ip_local_port_range = 1024 65000 表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为1024到65000。 
    net.ipv4.tcp_max_syn_backlog = 8192 表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。 
    net.ipv4.tcp_max_tw_buckets = 5000表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默 认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量,但是对于 Squid,效果却不大。此项参数可以控制TIME_WAIT套接字的最大数量,避免Squid服务器被大量的TIME_WAIT套接字拖死。 
    执行以下命令使配置生效: 
    /sbin/sysctl -p 

    http://dennis-zane.javaeye.com/blog/206963#comments 2008-06-23 TCP的TIME_WAIT状态 
    主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒,因而,TIME_WAIT状态一般维持在1-4分钟。 
    TIME_WAIT状态存在的理由: 
    1)可靠地实现TCP全双工连接的终止 
    在进行关闭连接四路握手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,因此客户端必须 维护状态信息允 许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在java中会抛出connection reset的SocketException)。因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭 的客户端必须维持状态信息进入TIME_WAIT状态。 
    2)允许老的重复分节在网络中消逝 
    TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个 原来的迷途分节就称为lost duplicate。在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身 (incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被无解成从属于新的化身。为了避免这个情 况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时 候,来自连接先前化身的重复分组已经在网络中消逝。 
    新的SCTP协议通过在消息头部添加验证标志避免了TIME_WAIT状态。

  • 相关阅读:
    BZOJ3615 : MSS
    BZOJ3468 : 滑雪
    BZOJ3515 : EvenPaths
    BZOJ3161 : 孤舟蓑笠翁
    BZOJ2652 : 三角板
    BZOJ2646 : neerc2011 flight
    BZOJ3567 : AABB
    HDU5823 : color II
    BZOJ1946 : [Ceoi2006]ANTENNA
    BZOJ4644 : 经典傻逼题
  • 原文地址:https://www.cnblogs.com/balaamwe/p/2279282.html
Copyright © 2020-2023  润新知