及时释放服务端与客户端之间的TCP连接的方法

及时释放服务端与客户端之间的TCP连接的方法

TCP的状态转换图

先贴上tcp状态转换图,方便后面分析问题

这里写图片描述

这里写图片描述

感知对端关闭,及时关闭己方连接

  前几天遇到了一个问题,服务端下线,主动断开了连接。但客户端并没有感知到,而是继续使用该连接,导致下次调用服务端报错。

  查看客户端和服务端的tcp状态,服务端处于FIN_WAIT_2状态,而客户端处于CLOSE_WAIT状态。

  结合上面四次挥手的图,分析原因。处于FIN_WAIT_2状态的服务端主动断开了连接,即在代码里调用了close()函数。而另一端响应主动方的断开请求,被动断开(这一过程是操作系统自动完成的),被动断开之后处于CLOSE_WAIT。之后再无其他动作,服务端认为断开了连接,而服务端仍然认为连接可用。

   如何避免这个问题呢,就是在服务端调用close之后,客户端感知到这个动作,然后向服务端发送一个FIN包,即调用close()方法。

  那么客户端可以感知到服务端的close动作吗?
  Java中我们使用Socket对象完成tcp的相关操作,其本身存在一些isConneted等函数判断连接的状态,但这些都是本地状态,无法感知到另一端的状态。有其他办法吗?一片很好的帖子给出了答案 https://stackoverflow.com/questions/10240694/java-socket-api-how-to-tell-if-a-connection-has-been-closed
其中提到了一条:

7. As a result of some experiments with Java 7 on Windows XP it also appears that if:

* you're selecting on OP_READ
select() returns a value of greater than zero
the associated SelectionKey is already invalid (key.isValid() == false)

it means the peer has reset the connection. However this may be peculiar to either the JRE version or platform.

   意思是在WindowsXP下,如果客户端主动关闭了连接服务端的select会停止阻塞,返回的SelectionKey判断isValid()会返回false。我本机是Win7系统,测试结果不太一样。Win7仍然返回的SelectionKey仍然是valid的,但是socketChannel.read(buffer)会返回-1,表明连接以及不可用。在Linux机器上的结果和本地Win7是一样的。
  另外,JDK官方的解释也没有说valid代表了远端是否关闭了连接:

A selection key is created each time a channel is registered with a selector. A key remains valid until it is cancelled by invoking its cancel method, by closing its channel, or by closing its selector. Cancelling a key does not immediately remove it from its selector; it is instead added to the selector's cancelled-key set for removal during the next selection operation. The validity of a key may be tested by invoking its isValid method.

主动关闭后,及时回收无效连接

   由于服务端需要处理大量连接,所以TCP是一个宝贵的资源,需要及时的回收。对于不可用的连接需要尽快的释放掉或者重用。

   某些情况下,服务端由于压力等原因需要断开某些连接。我们知道TCP连接断开需要四次回收,主动调用close方法并且客户端ack后只完成了两次挥手,此时的连接并没有完全关闭。那么,如果客户端一直不主动发送FIN包关闭,服务端就要一直保持连接吗?当然不是,系统会回收这样的连接,有一些参数控制了连接状态超时时间。有一篇文章总结了TCP协议中的超时机制http://blog.qiusuo.im/blog/2014/03/19/tcp-timeout/

   主动关闭后本地状态将进入FIN_WAIT_2 ,而FIN_WAIT_2 Timer就会及时回收掉本地端主动关闭远端却长时间不主动关闭的连接。其配置参数名字为tcp_fin_timeout 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值