服务器端nio的cpu 100%的疑问 本帖最后由 inthirties 于 2010-07-29 17:25:57 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 服务器端有对channel进行read的异常处理。按照我的想法,如果客户端的socket关闭了,那么这里read的时候应该有异常抛出的。不过这里居然还是可以read,没有异常,不过read的字节是0. 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的代码,只是用了读事件,没有用异步写。 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()); } } } 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 exceptionlogger.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());}}} 看网上说有jdk的bug 可能导致cpu 100%,所以升级到了6u21,还是不行,。 你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:key.cancel();key.channel().close();这样来关闭服务端与客户端的套接字,我好像也没看到这样的代码。 楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络情况比较恶劣的,可以优先解决掉.不用让系统超时地等待. Socket 没搞过 友情了 火龙果真是热情啊 就是一张读的都是0,客户端的程序都关闭了,服务器的socket还能读得到,也不抛错,socket不能检查到关闭。所以无法去判断什么时候cancel 有没有详细的对这个bug的描述呀。我现在也是想到用heartbeat包来进行检查了。原来也有心跳的检查,不过服务器端只是发hb包,由客户端自己主动放弃,以前是直接用socket来做的,这次这个客户端在线的负载要求的比较大,所以才转着用nio的,现在还是poc,觉得其他的都不错,就是这个问题没有解决。 客户端关闭以后,服务器端得socket都没有释放,lsof查看管道文件都没有释放,郁闷呀 1 协议上没有明确讲述这个问题2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.3 socket 是双向通道,只要有一方放弃;另一方就会自动断开. 客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。 一起用nio做客户端做压力测试,有过select空跑的情况。也就是while(true){try{selector.select();....}.....}也就是select取到事件,但是select()的返回是0,信任这个0,所以用这个返回做判断,造成select这里不停的空跑,不知道有没有兄弟也越到过这个问题,后来修改成最上面的代码,虽然比较恶心,但是还是解决了这个问题。 不知道mina里有没有这样的问题。有没有XDJM是用mina的有没有越到类似的问题。 客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netstat 看一下那个端口的状态 我也没碰到过这么奇怪的问题呢。看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。 在linux下用lsof查看client和serverclient程序关闭后 该pipe handle都没有,但是server端还有,没有释放。 1 程序问题是经常出现,而且是很频繁. 如果是出现的几率很高,我可以肯定答复你: Sorry , 我引导你到了一个错误的方向. 因为 TCP/IP 不会经常出现 "假连接";只有在一些网络环境极为恶劣的情况下出现.例如: 交换机或者路由器之间的网络切换,网络攻击等等.. 2 在Java 具体实现上我是初哥,在多线程方面暂时都是迷迷糊糊的.就不多讲了.继续关注下. 别这么客气刚才看了看在服务器上的和客户端的socket的状态是CLOSE_WAIT客户机的socket已经没有了。这样情况下从channel里读取没有异常,所以就没法进行异常的处理,关闭socket。 太怪异了。先用hb回给的方式来试试了,主要看性能能不能行了。给贴了,谢谢这里帮助的XDJM们,特别是火龙果和(Mark Liang)叻。以后有问题,再开新贴。 5月份的帖子,不知道你解决问题没, 以前我也遇到过read到0的事件, select的时候每次都返回一个read事件, 经检查,原来是ByteBuffer 复用照成的问题, 每次read时建议clear buffer, (如果buffer flip过,那么就会返回0,如果buffer读满了,照样会返回0, 在read到0的情况我们是不会关闭SelectionKey的,所以照成死循环)。 在nio方面java还是存在很多bug的。 在1.6u4以后貌似解决了。 Swing中怎么利用按钮刷新整个窗体 动作接口 关于Equals问题 JAVA 虚类简单问题。 JDBC和sqlserver连接,查询的异常 非专业问题 问大家一个语法问题? 先谢了 eclipse导出的jar程序应该怎么连接到mysql??? 大家请我吃饭吧,快抢书啊有用的太多了http://www.codestudy.net/book/default.asp 怎么在Applet中定时显示一数值? 多态问题 需求调研
{
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的代码,只是用了读事件,没有用异步写。
是把有事件的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());
}
}
}
是把有事件的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());
}
}
}
key.channel().close();这样来关闭服务端与客户端的套接字,我好像也没看到这样的代码。
友情了
火龙果真是热情啊
就是一张读的都是0,客户端的程序都关闭了,
服务器的socket还能读得到,也不抛错,socket不能检查到关闭。所以无法去判断什么时候cancel
有没有详细的对这个bug的描述呀。我现在也是想到用heartbeat包来进行检查了。原来也有心跳的检查,不过服务器端只是发hb包,由客户端自己主动放弃,以前是直接用socket来做的,这次这个客户端在线的负载要求的比较大,所以才转着用nio的,现在还是poc,觉得其他的都不错,就是这个问题没有解决。
客户端关闭以后,服务器端得socket都没有释放,lsof查看管道文件都没有释放,郁闷呀
2 不需要每时每刻监听,这样资源消耗肯定厉害.例如: 间隔30秒或者监听一次.
3 socket 是双向通道,只要有一方放弃;另一方就会自动断开.
客户端需要怎么断开哟。测试的客户端是用socket。close关闭的。也试过直接异常关闭程序。也就是ctrl+c都出现上面的问题。此时客户端的socket是关闭的。
select空跑的情况。也就是
while(true)
{
try
{
selector.select();
....
}
.....
}也就是select取到事件,但是select()的返回是0,信任这个0,所以用这个返回做判断,造成select这里不停的空跑,不知道有没有兄弟也越到过这个问题,后来修改成最上面的代码,虽然比较恶心,但是还是解决了这个问题。 不知道mina里有没有这样的问题。有没有XDJM是用mina的有没有越到类似的问题。
客户端启动后,找到对应的连接端口号,在客户端关闭后,再用 netstat 看一下那个端口的状态
在linux下用lsof查看client和serverclient程序关闭后 该pipe handle都没有,但是server端还有,没有释放。
2 在Java 具体实现上我是初哥,在多线程方面暂时都是迷迷糊糊的.就不多讲了.继续关注下.