服务器端nio的cpu 100%的疑问

时间:2022-09-05 12:03:24
服务器的程序是用nio写的

在linux环境下,遇到很怪的问题。

当客户端的socket关闭,正常程序关闭或者是客户端程序退出。

在服务端的selector还可以有事件被监听到,监听到的read事件,read为0,服务器端对应这个客户端的socket没有关闭,而且读不会有异常抛出。所以这样导致监听的线程空跑,cpu达到100%

不知道有没有同学解决过这样的问题的,怎么解决,高分谢谢。

43 个解决方案

#1


这具体要看代码了。

#2


当服务端得知客户端关闭了,服务端做了哪些处理?

#3


服务器端有对channel进行read的异常处理。

按照我的想法,如果客户端的socket关闭了,那么这里read的时候应该有异常抛出的。不过这里居然还是可以read,没有异常,不过read的字节是0. 

#4


代码我整理一下,帖上来,

帖服务器的代码就可以了吧。

#5


路过看看

#6


while(true)
{
try
{
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();

if (keys.size()>0) {
for (SelectionKey key : keys) 
{
if (key.isAcceptable()) 
{
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();

SocketChannel sc = ssc.accept();

logger.info("Accept " + sc.socket());

sc.configureBlocking(false);
sc.socket().setReceiveBufferSize(4096);
//sc.socket().setSoLinger(true, 0);
//sc.socket().setSoTimeout(1000*60);

sc.register(selector, SelectionKey.OP_READ);
sessionMgr.createSession(sc);
}
else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) 
{
requestQueueManager.receiveRequest((SocketChannel) key.channel());
}
}

keys.clear();
}
}
catch (CancelledKeyException e) {
logger.debug("Key is cancelled.<"+e.getMessage()+">");
} catch (IOException e) {
logger.error("Process Error: ", e);
}
}
}

这是监听accept,并且注册read的代码,只是用了读事件,没有用异步写。

#7


该回复于2010-07-30 10:08:51被版主删除

#8


requestQueueManager.receiveRequest((SocketChannel) key.channel());
是把有事件的channel push到一个link里。

然后在用一个processThreadPool对每个link里的channel进行处理。

while (runflag) {
if ((channel = requestQueueManager.pollRequestChannel()) != null) {
try 
{
processRequest(channel);
}
catch (NullPointerException e1) {
logger.error("Read Data error: " + channel);
}
catch (Exception ex) {
logger.error("Read Data error: ", ex);

try
{
serverProcessor.beforeDiscard(channel);
}
catch (Exception e) {
// TODO: handle exception
logger.warn("before discard connection error. As " + e.getMessage());
}

sessionManager.closeSessionByChannel(channel);
}
}
else
{
try 
{
TimeUnit.MILLISECONDS.sleep(100);

catch (InterruptedException e) 
{
logger.warn("Sleep error. As " + e.getMessage());
}
}
}

#9


requestQueueManager.receiveRequest((SocketChannel) key.channel());
是把有事件的channel push到一个link里。

然后在用一个processThreadPool对每个link里的channel进行处理。

processRequest(channel);就是处理channel的地方,这里就是没有异常出来,而且channel看到的居然还是open的。

while (runflag) {
if (( channel = requestQueueManager.pollRequestChannel()) != null) {
try 
{
processRequest(channel);
}
catch (NullPointerException e1) {
logger.error("Read Data error: " + channel);
}
catch (Exception ex) {
logger.error("Read Data error: ", ex);

try
{
serverProcessor.beforeDiscard(channel);
}
catch (Exception e) {
// TODO: handle exception
logger.warn("before discard connection error. As " + e.getMessage());
}

sessionManager.closeSessionByChannel(channel);
}
}
else
{
try 
{
TimeUnit.MILLISECONDS.sleep(100);

catch (InterruptedException e) 
{
logger.warn("Sleep error. As " + e.getMessage());
}
}
}

#10


看网上说有jdk的bug 可能导致cpu 100%,所以升级到了6u21,还是不行,。

#11


你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel().close();

这样来关闭服务端与客户端的套接字,我好像也没看到这样的代码。

#12


这位 很n

#13


楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.

当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络情况比较恶劣的,可以优先解决掉.不用让系统超时地等待. 

#14


  Socket  没搞过  
    友情了
   火龙果真是热情啊

#15


引用 11 楼 bao110908 的回复:
你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel()……


就是一张读的都是0,客户端的程序都关闭了,
服务器的socket还能读得到,也不抛错,socket不能检查到关闭。所以无法去判断什么时候cancel

#16


引用 13 楼 ljf_ljf 的回复:
楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.

当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络……


有没有详细的对这个bug的描述呀。

我现在也是想到用heartbeat包来进行检查了。原来也有心跳的检查,不过服务器端只是发hb包,由客户端自己主动放弃,以前是直接用socket来做的,这次这个客户端在线的负载要求的比较大,所以才转着用nio的,现在还是poc,觉得其他的都不错,就是这个问题没有解决。

#17


引用 11 楼 bao110908 的回复:
你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel()……


客户端关闭以后,服务器端得socket都没有释放,lsof查看管道文件都没有释放,郁闷呀

#18


自己写的? 连接时消息都能收到? 客户端断开时就监听不到了?

#19


1 协议上没有明确讲述这个问题
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
3 socket 是双向通道,只要有一方放弃;另一方就会自动断开. 

#20


如果是这样的话,很可能客户端断开有问题。

#21


引用 14 楼 bolink5 的回复:
Socket 没搞过  
  友情了
  火龙果真是热情啊

不懂 帮顶

#22


引用 19 楼 ljf_ljf 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能

3 socket 是双向通道,只要有一方放弃;另一方就会自动断开.
个人理解是这样的,但是这次遇到的问题,就是就是困惑这点,如果是这样的,client的程序断掉,server的socket怎么没有关闭了,而且read居然没有错误。

#23


引用 21 楼 cl61917380 的回复:
引用 14 楼 bolink5 的回复:
Socket 没搞过
友情了
火龙果真是热情啊

不懂 帮顶


非常谢谢,。

#24


引用 20 楼 bao110908 的回复:
如果是这样的话,很可能客户端断开有问题。


客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。

#25


该回复于2010-08-06 17:04:15被版主删除

#26


引用 25 楼 czp0608 的回复:
每天回帖即可获得10分可用分!小技巧


good habit

#27


一起用nio做客户端做压力测试,有过
select空跑的情况。

也就是
while(true)
{
try
{
selector.select();
....
}
.....
}

也就是select取到事件,但是select()的返回是0,信任这个0,所以用这个返回做判断,造成select这里不停的空跑,不知道有没有兄弟也越到过这个问题,后来修改成最上面的代码,虽然比较恶心,但是还是解决了这个问题。 不知道mina里有没有这样的问题。有没有XDJM是用mina的有没有越到类似的问题。

#28


顶一下,做个标记,顺便获得每日10分可用分。

#29


学习学习

#30


引用 22 楼 inthirties 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能
RE: 首先,增加心跳包是有必要的;主要是检查Socket的健壮性。 
CPU 空跑是什么意思呢?如果只是暂用一下CPU资源,个人认为还是可以的;另外,楼主3秒监听一次,也太频繁了吧。我之前做的是游戏平台的内容,按经验来讲一般是20 ~ 30 秒之间 做一次心跳包就可以了。


3 socket 是双向通道,只要有一方放弃;另一方就会自动断开.
个人理解是这样的,但是这次遇到的问题,就是就是困惑这点,如果是这样的,client的程序断掉,server的socket怎么……
RE:这个问题我也是郁闷中地寻求答案,一直都没有什么头绪解决这个问题。在没有了解清楚之前,只能是继续按着之前的了解去做。

#31


引用 30 楼 ljf_ljf 的回复:
引用 22 楼 inthirties 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能
RE: 首先,增加心跳包是有必要的;主要是检查Socket的健壮性。
CPU 空跑是什么意思呢?如果只是暂用一下CPU资源,个人认为还是可以的;另外,楼主3秒监听一次,也太频繁了吧。我之前做的是游戏……
是的,非常同意你对心跳包的理解。我们也加了心跳包,不过由于服务器要承担比较大的长连接数量,所以心跳包现在只是有server发自client,然后client进行判断,3秒主要是我们的数据延迟的限制,如果三秒没有相应的话,客户端需要一定的处理。
CPU空跑,主要是发现的这个问题导致的。就是不听的执行loop,但是loop里什么都不做,这里由于这个问题,select还是可以发现有事件进来(read事件),read的字节是0,所以也就是什么都没有。这样就类似于一个无限死循环一样。
现在个人的想法,是想client响应hb包,然后server端根据相应来判断socket是不是有异状,如果没有收到client过来的,则在server端,cancel掉该key。不过这样的话,还是不能避免CPU空跑的问题,不过是空跑到心跳包发现问题,才进行阻止。这样估计对我们的负载和性能还是有比较大的影响的。
所以,正不知道该怎么来处理好这个问题了。

#32


引用 24 楼 inthirties 的回复:
引用 20 楼 bao110908 的回复:

如果是这样的话,很可能客户端断开有问题。

客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。


客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netstat 看一下那个端口的状态

#33


我也没碰到过这么奇怪的问题呢。

看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。

#34


引用 32 楼 bao110908 的回复:
引用 24 楼 inthirties 的回复:

引用 20 楼 bao110908 的回复:

如果是这样的话,很可能客户端断开有问题。

客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。


客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netst……


在linux下用lsof查看client和server

client程序关闭后 该pipe handle都没有,但是server端还有,没有释放。

#35


哦,这样啊。

我一般查看端口状态的,呵呵。

#36


引用 35 楼 bao110908 的回复:
哦,这样啊。

我一般查看端口状态的,呵呵。


差不多的功能。表现的形式不一样而已。

嘻嘻嘻。

#37


引用 33 楼 bao110908 的回复:
我也没碰到过这么奇怪的问题呢。

看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。


isOpen返回是true呀。

#38


 1 程序问题是经常出现,而且是很频繁. 如果是出现的几率很高,我可以肯定答复你: Sorry , 我引导你到了一个错误的方向. 因为 TCP/IP 不会经常出现 "假连接";只有在一些网络环境极为恶劣的情况下出现.例如: 交换机或者路由器之间的网络切换,网络攻击等等..
 2 在Java 具体实现上我是初哥,在多线程方面暂时都是迷迷糊糊的.就不多讲了.继续关注下.

#39


别这么客气

刚才看了看在服务器上的和客户端的socket的状态是CLOSE_WAIT

客户机的socket已经没有了。

这样情况下从channel里读取没有异常,所以就没法进行异常的处理,关闭socket。

#40


太怪异了。先用hb回给的方式来试试了,主要看性能能不能行了。

给贴了,

谢谢这里帮助的XDJM们,特别是火龙果和(Mark Liang)叻。

以后有问题,再开新贴。

#41


你分给错了吧!!

#42


你这个问题最后是怎么解决的?我也遇到一样的问题

#43


5月份的帖子,不知道你解决问题没, 以前我也遇到过read到0的事件,   select的时候每次都返回一个read事件,  经检查,原来是ByteBuffer  复用照成的问题,    每次read时建议clear  buffer,  (如果buffer flip过,那么就会返回0,如果buffer读满了,照样会返回0,  在read到0的情况我们是不会关闭SelectionKey的,所以照成死循环)。  在nio方面java还是存在很多bug的。  在1.6u4以后貌似解决了。

#1


这具体要看代码了。

#2


当服务端得知客户端关闭了,服务端做了哪些处理?

#3


服务器端有对channel进行read的异常处理。

按照我的想法,如果客户端的socket关闭了,那么这里read的时候应该有异常抛出的。不过这里居然还是可以read,没有异常,不过read的字节是0. 

#4


代码我整理一下,帖上来,

帖服务器的代码就可以了吧。

#5


路过看看

#6


while(true)
{
try
{
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();

if (keys.size()>0) {
for (SelectionKey key : keys) 
{
if (key.isAcceptable()) 
{
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();

SocketChannel sc = ssc.accept();

logger.info("Accept " + sc.socket());

sc.configureBlocking(false);
sc.socket().setReceiveBufferSize(4096);
//sc.socket().setSoLinger(true, 0);
//sc.socket().setSoTimeout(1000*60);

sc.register(selector, SelectionKey.OP_READ);
sessionMgr.createSession(sc);
}
else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) 
{
requestQueueManager.receiveRequest((SocketChannel) key.channel());
}
}

keys.clear();
}
}
catch (CancelledKeyException e) {
logger.debug("Key is cancelled.<"+e.getMessage()+">");
} catch (IOException e) {
logger.error("Process Error: ", e);
}
}
}

这是监听accept,并且注册read的代码,只是用了读事件,没有用异步写。

#7


该回复于2010-07-30 10:08:51被版主删除

#8


requestQueueManager.receiveRequest((SocketChannel) key.channel());
是把有事件的channel push到一个link里。

然后在用一个processThreadPool对每个link里的channel进行处理。

while (runflag) {
if ((channel = requestQueueManager.pollRequestChannel()) != null) {
try 
{
processRequest(channel);
}
catch (NullPointerException e1) {
logger.error("Read Data error: " + channel);
}
catch (Exception ex) {
logger.error("Read Data error: ", ex);

try
{
serverProcessor.beforeDiscard(channel);
}
catch (Exception e) {
// TODO: handle exception
logger.warn("before discard connection error. As " + e.getMessage());
}

sessionManager.closeSessionByChannel(channel);
}
}
else
{
try 
{
TimeUnit.MILLISECONDS.sleep(100);

catch (InterruptedException e) 
{
logger.warn("Sleep error. As " + e.getMessage());
}
}
}

#9


requestQueueManager.receiveRequest((SocketChannel) key.channel());
是把有事件的channel push到一个link里。

然后在用一个processThreadPool对每个link里的channel进行处理。

processRequest(channel);就是处理channel的地方,这里就是没有异常出来,而且channel看到的居然还是open的。

while (runflag) {
if (( channel = requestQueueManager.pollRequestChannel()) != null) {
try 
{
processRequest(channel);
}
catch (NullPointerException e1) {
logger.error("Read Data error: " + channel);
}
catch (Exception ex) {
logger.error("Read Data error: ", ex);

try
{
serverProcessor.beforeDiscard(channel);
}
catch (Exception e) {
// TODO: handle exception
logger.warn("before discard connection error. As " + e.getMessage());
}

sessionManager.closeSessionByChannel(channel);
}
}
else
{
try 
{
TimeUnit.MILLISECONDS.sleep(100);

catch (InterruptedException e) 
{
logger.warn("Sleep error. As " + e.getMessage());
}
}
}

#10


看网上说有jdk的bug 可能导致cpu 100%,所以升级到了6u21,还是不行,。

#11


你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel().close();

这样来关闭服务端与客户端的套接字,我好像也没看到这样的代码。

#12


这位 很n

#13


楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.

当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络情况比较恶劣的,可以优先解决掉.不用让系统超时地等待. 

#14


  Socket  没搞过  
    友情了
   火龙果真是热情啊

#15


引用 11 楼 bao110908 的回复:
你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel()……


就是一张读的都是0,客户端的程序都关闭了,
服务器的socket还能读得到,也不抛错,socket不能检查到关闭。所以无法去判断什么时候cancel

#16


引用 13 楼 ljf_ljf 的回复:
楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.

当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络……


有没有详细的对这个bug的描述呀。

我现在也是想到用heartbeat包来进行检查了。原来也有心跳的检查,不过服务器端只是发hb包,由客户端自己主动放弃,以前是直接用socket来做的,这次这个客户端在线的负载要求的比较大,所以才转着用nio的,现在还是poc,觉得其他的都不错,就是这个问题没有解决。

#17


引用 11 楼 bao110908 的回复:
你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?

一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?

如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:

key.cancel();
key.channel()……


客户端关闭以后,服务器端得socket都没有释放,lsof查看管道文件都没有释放,郁闷呀

#18


自己写的? 连接时消息都能收到? 客户端断开时就监听不到了?

#19


1 协议上没有明确讲述这个问题
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
3 socket 是双向通道,只要有一方放弃;另一方就会自动断开. 

#20


如果是这样的话,很可能客户端断开有问题。

#21


引用 14 楼 bolink5 的回复:
Socket 没搞过  
  友情了
  火龙果真是热情啊

不懂 帮顶

#22


引用 19 楼 ljf_ljf 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能

3 socket 是双向通道,只要有一方放弃;另一方就会自动断开.
个人理解是这样的,但是这次遇到的问题,就是就是困惑这点,如果是这样的,client的程序断掉,server的socket怎么没有关闭了,而且read居然没有错误。

#23


引用 21 楼 cl61917380 的回复:
引用 14 楼 bolink5 的回复:
Socket 没搞过
友情了
火龙果真是热情啊

不懂 帮顶


非常谢谢,。

#24


引用 20 楼 bao110908 的回复:
如果是这样的话,很可能客户端断开有问题。


客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。

#25


该回复于2010-08-06 17:04:15被版主删除

#26


引用 25 楼 czp0608 的回复:
每天回帖即可获得10分可用分!小技巧


good habit

#27


一起用nio做客户端做压力测试,有过
select空跑的情况。

也就是
while(true)
{
try
{
selector.select();
....
}
.....
}

也就是select取到事件,但是select()的返回是0,信任这个0,所以用这个返回做判断,造成select这里不停的空跑,不知道有没有兄弟也越到过这个问题,后来修改成最上面的代码,虽然比较恶心,但是还是解决了这个问题。 不知道mina里有没有这样的问题。有没有XDJM是用mina的有没有越到类似的问题。

#28


顶一下,做个标记,顺便获得每日10分可用分。

#29


学习学习

#30


引用 22 楼 inthirties 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能
RE: 首先,增加心跳包是有必要的;主要是检查Socket的健壮性。 
CPU 空跑是什么意思呢?如果只是暂用一下CPU资源,个人认为还是可以的;另外,楼主3秒监听一次,也太频繁了吧。我之前做的是游戏平台的内容,按经验来讲一般是20 ~ 30 秒之间 做一次心跳包就可以了。


3 socket 是双向通道,只要有一方放弃;另一方就会自动断开.
个人理解是这样的,但是这次遇到的问题,就是就是困惑这点,如果是这样的,client的程序断掉,server的socket怎么……
RE:这个问题我也是郁闷中地寻求答案,一直都没有什么头绪解决这个问题。在没有了解清楚之前,只能是继续按着之前的了解去做。

#31


引用 30 楼 ljf_ljf 的回复:
引用 22 楼 inthirties 的回复:
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
hb包基本上是3秒一次,不过这样3秒内,cpu还是有空跑的可能
RE: 首先,增加心跳包是有必要的;主要是检查Socket的健壮性。
CPU 空跑是什么意思呢?如果只是暂用一下CPU资源,个人认为还是可以的;另外,楼主3秒监听一次,也太频繁了吧。我之前做的是游戏……
是的,非常同意你对心跳包的理解。我们也加了心跳包,不过由于服务器要承担比较大的长连接数量,所以心跳包现在只是有server发自client,然后client进行判断,3秒主要是我们的数据延迟的限制,如果三秒没有相应的话,客户端需要一定的处理。
CPU空跑,主要是发现的这个问题导致的。就是不听的执行loop,但是loop里什么都不做,这里由于这个问题,select还是可以发现有事件进来(read事件),read的字节是0,所以也就是什么都没有。这样就类似于一个无限死循环一样。
现在个人的想法,是想client响应hb包,然后server端根据相应来判断socket是不是有异状,如果没有收到client过来的,则在server端,cancel掉该key。不过这样的话,还是不能避免CPU空跑的问题,不过是空跑到心跳包发现问题,才进行阻止。这样估计对我们的负载和性能还是有比较大的影响的。
所以,正不知道该怎么来处理好这个问题了。

#32


引用 24 楼 inthirties 的回复:
引用 20 楼 bao110908 的回复:

如果是这样的话,很可能客户端断开有问题。

客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。


客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netstat 看一下那个端口的状态

#33


我也没碰到过这么奇怪的问题呢。

看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。

#34


引用 32 楼 bao110908 的回复:
引用 24 楼 inthirties 的回复:

引用 20 楼 bao110908 的回复:

如果是这样的话,很可能客户端断开有问题。

客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。


客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netst……


在linux下用lsof查看client和server

client程序关闭后 该pipe handle都没有,但是server端还有,没有释放。

#35


哦,这样啊。

我一般查看端口状态的,呵呵。

#36


引用 35 楼 bao110908 的回复:
哦,这样啊。

我一般查看端口状态的,呵呵。


差不多的功能。表现的形式不一样而已。

嘻嘻嘻。

#37


引用 33 楼 bao110908 的回复:
我也没碰到过这么奇怪的问题呢。

看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。


isOpen返回是true呀。

#38


 1 程序问题是经常出现,而且是很频繁. 如果是出现的几率很高,我可以肯定答复你: Sorry , 我引导你到了一个错误的方向. 因为 TCP/IP 不会经常出现 "假连接";只有在一些网络环境极为恶劣的情况下出现.例如: 交换机或者路由器之间的网络切换,网络攻击等等..
 2 在Java 具体实现上我是初哥,在多线程方面暂时都是迷迷糊糊的.就不多讲了.继续关注下.

#39


别这么客气

刚才看了看在服务器上的和客户端的socket的状态是CLOSE_WAIT

客户机的socket已经没有了。

这样情况下从channel里读取没有异常,所以就没法进行异常的处理,关闭socket。

#40


太怪异了。先用hb回给的方式来试试了,主要看性能能不能行了。

给贴了,

谢谢这里帮助的XDJM们,特别是火龙果和(Mark Liang)叻。

以后有问题,再开新贴。

#41


你分给错了吧!!

#42


你这个问题最后是怎么解决的?我也遇到一样的问题

#43


5月份的帖子,不知道你解决问题没, 以前我也遇到过read到0的事件,   select的时候每次都返回一个read事件,  经检查,原来是ByteBuffer  复用照成的问题,    每次read时建议clear  buffer,  (如果buffer flip过,那么就会返回0,如果buffer读满了,照样会返回0,  在read到0的情况我们是不会关闭SelectionKey的,所以照成死循环)。  在nio方面java还是存在很多bug的。  在1.6u4以后貌似解决了。