逍遥游

如何正确的检测TCP SOCKET连接的有效性

这是花费了两个小时换来的“血”的教训啊

写在最前面的依旧是一大段废话

来龙去脉

今天阿里发来一封邮件说我的服务器CPU达到了90%!很是震惊啊,这台服务器仅仅跑了一个java写的app服务器而已,而且只有我一个人测试用。
于是好奇地登上后台,发现已经超高CPU(100%)好久了,都不知道是什么时候开始的。。。估计了一下,应该是我的java程序有什么漏洞,再加上最近没有做什么大的改动,估计两个月之前运行的时候就已经占满CPU了,一直被蒙在鼓里。
登上服务器,top一下,果然java进程独占CPU啊。。。
首先看了下程序输出,异常的正常。。。又检查了一遍源代码,没有头绪,看网上说用strace检查进程状态,但是看来看去只有futex一行,折腾来折腾去,查不出毛病,于是尝试还原BUG。
经过几次尝试,发现每次app上用户退出时,CPU就会瞬间飙升到100,于是检查socket部分。
我的代码大体是如此写的

1
2
3
4
5
6
7
8
while(socket.isConnect())
{
String str = socket.readLine();
if(str==null)
continue;
//handle str and write
}
socket.close();

在readLine后加上输出调试代码,于是当我退出app时,服务器控制台的输出真的是如滔滔江水啊,结束之后日志文件大概写了1个G数据。。。密密麻麻全部是null,终于定位到错误点了,把continue改成break,至此,解决。

那么,

如何正确有效的判断socket连接是否还有效呢

首先,说一下我用来判断的那个坑爹的函数
isClosed() 字面上意思是判断是否socket已关闭,然而它的真正含义是判断己方的socket是否关闭,这个跟建立起来的链路没有半毛钱关系。也就是说,除非己方执行了soket.close()操作,否则这个就是一直返回false(从连接建立开始算)。真是个鸡肋的函数

还有这个,
isConnected() 实际上是告诉你是否执行了连接操作,只要不执行socket.close(),始终返回true

socket通信中,一方关闭连接并不会自动告知对方,另一方只有在read或者write的时候才能发现异常,并且write会抛出异常,而read一般不会

当一方结束通信时,另一方read的结果是:(JAVA)
read 返回 -1
readLine 返回 null
readXXX 抛出异常

write会抛出IOException

然后给出一个比较好一点的判断方法

解决方案

通过read的结果判断连接是否已经中断,再加上try catch

1
2
3
4
5
6
7
8
9
10
try{
String str = socket.readLine();
while(str != null)
{
//do something
str = socket.readLine();
}
}catch(IOException ex){
}

附上两篇参考文章:
Java socket API: How to tell if a connection has been closed?
有关Java中isClosed()和isConnected()的一些误解


多说停止服务,disqus引导注册太过分,暂时不上评论系统了。有机会自己造轮子吧。邮箱:input@newnius.com