本帖最后由 inthirties 于 2010-07-29 17:25:57 编辑

解决方案 »

  1.   

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

  2.   

    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的代码,只是用了读事件,没有用异步写。
      

  3.   

    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());
    }
    }
    }
      

  4.   

    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());
    }
    }
    }
      

  5.   

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

  6.   

    你看一下客户端关闭后,用 netstat 查看客户端、服务端上之前的通信端口是什么状态?一般服务端用 read 读到 -1 时,就表示客户端关掉了,读到是 0 的话根据 API DOC 描述也是有可能的。是不是客户端关掉后,服务端一直读到 0?如果服务端检查到客户端关闭的话,需要在 SelectionKey 上调用:key.cancel();
    key.channel().close();这样来关闭服务端与客户端的套接字,我好像也没看到这样的代码。
      

  7.   

    楼主,在C++ 上面也会有这样的情况.之前,我差过一些相关资料.发现好像是TCP/IP 协议的一个底层的Bug, 就是在某些情况下出现一些假的Socket 连接.当时,我的解决方法就是对没一条Socket 增加心跳包的检测;若发现心跳包不能正常返回就认为这个Socket 连接时已经失效了. 这样一方面可以避免假连接的出现.另一方面,也可以主动去检查各个客户端连接上来的网络情况.若出现网络情况比较恶劣的,可以优先解决掉.不用让系统超时地等待. 
      

  8.   

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

  9.   


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

  10.   


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

  11.   


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

  12.   

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

  13.   


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

  14.   

    一起用nio做客户端做压力测试,有过
    select空跑的情况。也就是
    while(true)
    {
    try
    {
    selector.select();
    ....
    }
    .....
    }也就是select取到事件,但是select()的返回是0,信任这个0,所以用这个返回做判断,造成select这里不停的空跑,不知道有没有兄弟也越到过这个问题,后来修改成最上面的代码,虽然比较恶心,但是还是解决了这个问题。 不知道mina里有没有这样的问题。有没有XDJM是用mina的有没有越到类似的问题。
      

  15.   


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

  16.   

    我也没碰到过这么奇怪的问题呢。看了一下 SocketChannel 实现的源代码,SocketChannel#read 在 SocketChannel#isOpen 返回 false 的情况下会直接返回 0。所以看一下 SocketChannel#isOpen 方法返回的是什么。
      

  17.   


    在linux下用lsof查看client和serverclient程序关闭后 该pipe handle都没有,但是server端还有,没有释放。
      

  18.   

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

  19.   

    别这么客气刚才看了看在服务器上的和客户端的socket的状态是CLOSE_WAIT客户机的socket已经没有了。这样情况下从channel里读取没有异常,所以就没法进行异常的处理,关闭socket。
      

  20.   

    太怪异了。先用hb回给的方式来试试了,主要看性能能不能行了。给贴了,谢谢这里帮助的XDJM们,特别是火龙果和(Mark Liang)叻。以后有问题,再开新贴。
      

  21.   

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