返回列表 发帖

[疯狂Java讲义] 《疯狂JAVA讲义》中Selector使用中的问题

对于<<疯狂Java讲义>>第828页中间代码中 讲NClient.java程序时
其中有如下代码
  1.      for (SelectionKey sk : selector.selectedKeys())
  2.      {
  3.       //删除正在处理的SelectionKey
  4.       selector.selectedKeys().remove(sk);
  5.       //如果该SelectionKey对应的Channel中有可读的数据
  6.       if (sk.isReadable())
  7.       {
  8.        //使用NIO读取Channel中的数据
  9.        SocketChannel sc = (SocketChannel)sk.channel();
  10.        ByteBuffer buff = ByteBuffer.allocate(1024);
  11.        String content = "";
  12.        while(sc.read(buff) > 0)
  13.        {
  14.         sc.read(buff);
  15.         buff.flip();
  16.         content += charset.decode(buff);
  17.        }
  18.        //打印输出读取的内容
  19.        System.out.println("聊天信息:" + content);
  20.        //为下一次读取作准备
  21.        sk.interestOps(SelectionKey.OP_READ);
  22.       }
  23.      }
复制代码


对于如上代码
  1.       //删除正在处理的SelectionKey
  2.       selector.selectedKeys().remove(sk);
复制代码


为什么不是放在for循环的最后一句,而是放在开头呢?正常理解应该是处理完了,再remove掉.虽然,我发现在放在最后和放在最前面的结果是一样的!
对应我有三点想问一下

第一点:
从理解的角度来看,应该是上面处理完了,再来个 selector.selectedKeys().remove(sk);啊

第二点:
当我们selector.selectedKeys().remove(sk);
已经删除掉了sk,为什么下面还能继续使用sk来调用它的方法呢? 如 sk.isReadable()

第三点
当我们已经selector.selectedKeys().remove(sk);
在SelectionKey集合通过keys方法中还包含这个sk对象吗? (我认为是应该有的,只是没有进行IO处理了)


selectedKeys()返回是被选择需要进行io处理的Channel.
keys()方法返回则是所有注册在该Selector()上的Channel

提问赏金:6金币
获奖名单 : robin(6金币)    
倚楼听风雨,笑看江湖路。。。

没有用过NIO,不过可以从集合的角度去解答你的问题
对于问题1、2:
selector.selectedKeys().remove(sk);  只是从selector.selectedKeys() 集合里面删除sk对象,
并不是把这个sk 对象本身销毁,所以这个对象还是有效的

问题3:在SelectionKey集合通过keys方法中还包含这个sk对象吗?
你说的SelectionKey集合指的是什么?是不是指selector的keys方法?如果是的话remove之后就不会包含了

TOP

原帖由 robin 于 2009-4-12 20:39 发表
没有用过NIO,不过可以从集合的角度去解答你的问题
对于问题1、2:
selector.selectedKeys().remove(sk);  只是从selector.selectedKeys() 集合里面删除sk对象,
并不是把这个sk 对象本身销毁,所以这个对象还是有效的

问题 ...


谢谢robin兄弟的回复!
问题1,2的原因,我认为兄弟说的应该是正确的

问题3:在SelectionKey集合通过keys方法中还包含这个sk对象吗?
是指的指selector的keys方法
不过,selector.selectedKeys().remove(sk);
应该只是删除在selector上需要进行io处理的SelecttionKey,但是在selector上注册的SelectionKey应该还是在的,根据
selectedKeys()返回是被选择需要进行io处理的Channel.
keys()方法返回则是所有注册在该Selector()上的Channel

哦,书上这样的解释说明的,我的理解认为应该是这样的
倚楼听风雨,笑看江湖路。。。

TOP

TOP

倚楼听风雨,笑看江湖路。。。

TOP

最近也在用nio,也是搞不懂这行代码selector.selectedKeys().remove(sk);这行代码到底起了怎样的作用?
麻烦heyitang讲讲啊

[ 本帖最后由 leeyohn 于 2010-2-2 10:55 编辑 ]
万里独行多陌路,一诗好赏便知音。

TOP

原帖由 leeyohn 于 2010-2-2 10:54 发表
最近也在用nio,也是搞不懂这行代码selector.selectedKeys().remove(sk);这行代码到底起了怎样的作用?
麻烦heyitang讲讲啊


不好意思,以后没有看到这个帖子
你看看该书 826页 最下面的一段代码就知道了
(代码我附在最下面了)
下面之所以remove,是保证下面服务器端 对所有客户端的Channel广播消息时,不用发送给自己,确切一点说,就是向其它客户端的Channel输出的时候,排除掉当前自己发送过来的信息,让他不用收到自己发送过来的消息。。



  1. import java.io.*;
  2. import java.nio.*;
  3. import java.nio.channels.*;
  4. import java.nio.channels.spi.*;
  5. import java.net.*;
  6. import java.util.*;
  7. import java.nio.charset.*;
  8. /**
  9. * Description:
  10. * <br/>Copyright (C), 2008-2010, Yeeku.H.Lee
  11. * <br/>This program is protected by copyright laws.
  12. * <br/>Program Name:
  13. * <br/>Date:
  14. * @author  Yeeku.H.Lee kongyeeku@163.com
  15. * @version  1.0
  16. */
  17. public class NServer
  18. {
  19. //用于检测所有Channel状态的Selector
  20. private Selector selector = null;
  21. //定义实现编码、解码的字符集对象
  22. private Charset charset = Charset.forName("UTF-8");
  23.     public void init()throws IOException
  24.     {
  25.   selector = Selector.open();
  26.   //通过open方法来打开一个未绑定的ServerSocketChannel实例
  27.   ServerSocketChannel server = ServerSocketChannel.open();
  28.   InetSocketAddress isa = new InetSocketAddress(
  29.    "127.0.0.1", 30000);
  30.   //将该ServerSocketChannel绑定到指定IP地址
  31.   server.socket().bind(isa);
  32.   //设置ServerSocket以非阻塞方式工作
  33.   server.configureBlocking(false);
  34.   //将server注册到指定Selector对象
  35.   server.register(selector, SelectionKey.OP_ACCEPT);
  36.   while (selector.select() > 0)
  37.   {
  38.    //依次处理selector上的每个已选择的SelectionKey
  39.    for (SelectionKey sk : selector.selectedKeys())
  40.    {
  41.     //从selector上的已选择Key集中删除正在处理的SelectionKey
  42.     selector.selectedKeys().remove(sk);
  43.     //如果sk对应的通道包含客户端的连接请求
  44.     if (sk.isAcceptable())
  45.     {
  46.      //调用accept方法接受连接,产生服务器端对应的SocketChannel
  47.      SocketChannel sc = server.accept();
  48.      //设置采用非阻塞模式
  49.      sc.configureBlocking(false);
  50.      //将该SocketChannel也注册到selector
  51.      sc.register(selector, SelectionKey.OP_READ);
  52.      //将sk对应的Channel设置成准备接受其他请求
  53.      sk.interestOps(SelectionKey.OP_ACCEPT);
  54.     }
  55.     //如果sk对应的通道有数据需要读取
  56.     if (sk.isReadable())
  57.     {
  58.      //获取该SelectionKey对应的Channel,该Channel中有可读的数据
  59.      SocketChannel sc = (SocketChannel)sk.channel();
  60.      //定义准备执行读取数据的ByteBuffer
  61.      ByteBuffer buff = ByteBuffer.allocate(1024);
  62.      String content = "";
  63.      //开始读取数据
  64.      try
  65.      {
  66.       while(sc.read(buff) > 0)
  67.       {
  68.        buff.flip();
  69.        content += charset.decode(buff);
  70.       }
  71.       //打印从该sk对应的Channel里读取到的数据
  72.       System.out.println("=====" + content);
  73.       //将sk对应的Channel设置成准备下一次读取
  74.       sk.interestOps(SelectionKey.OP_READ);
  75.      }
  76.      //如果捕捉到该sk对应的Channel出现了异常,即表明该Channel
  77.      //对应的Client出现了问题,所以从Selector中取消sk的注册
  78.      catch (IOException ex)
  79.      {
  80.       //从Selector中删除指定的SelectionKey
  81.       sk.cancel();
  82.       if (sk.channel() != null)
  83.       {
  84.        sk.channel().close();
  85.       }
  86.      }
  87.      //如果content的长度大于0,即聊天信息不为空
  88.      if (content.length() > 0)
  89.      {
  90.       //遍历该selector里注册的所有SelectKey
  91.       for (SelectionKey key : selector.keys())
  92.       {
  93.        //获取该key对应的Channel
  94.        Channel targetChannel = key.channel();
  95.        //如果该channel是SocketChannel对象
  96.        if (targetChannel instanceof SocketChannel)
  97.        {
  98.         //将读到的内容写入该Channel中
  99.         SocketChannel dest = (SocketChannel)targetChannel;
  100.         dest.write(charset.encode(content));
  101.        }
  102.       }
  103.      }
  104.     }
  105.    }
  106.   }
  107.     }

  108. public static void main(String[] args)
  109.   throws IOException
  110. {
  111.   new NServer().init();
  112. }
  113. }
复制代码
倚楼听风雨,笑看江湖路。。。

TOP

返回列表