2012-02-17 72 views
1

我遇到了使用选择器的问题。如何正确使用NIO选择器?

我写了一些测试代码,尝试在服务器端使用Selector创建客户端/服务器连接以管理通道。问题是,当Selector选择要读取的通道并且处理读取操作时,实际上没有数据被读取。

我发布了这个问题在another forum并且还没有收到任何答案。

服务器:

static class Server implements Runnable { 
    Selector sel; 

    @Override 
    public void run() { 
     try { 
      ServerSocketChannel server = ServerSocketChannel.open(); 
      server.socket().bind(new InetSocketAddress(5555)); 
      server.configureBlocking(false); 
      sel = Selector.open(); 
      server.register(sel, SelectionKey.OP_ACCEPT); 

      boolean running = true; 
      while(running) { 
       int count = sel.select(); 
       if(sel.isOpen() && count > 0) { 
        Set<SelectionKey> keyset = sel.selectedKeys(); 
        synchronized(keyset) { 
         Iterator<SelectionKey> i = keyset.iterator(); 
         while(i.hasNext()) { 
          SelectionKey key = i.next(); 
          i.remove(); 
          processKey(key); 
         } 
        } 
       } else if(!sel.isOpen()) 
        running = false; 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void processKey(SelectionKey key) { 

     if(key.isValid() && key.isAcceptable()) { 
      try { 
       SocketChannel chan = ((ServerSocketChannel)key.channel()).accept(); 
       chan.configureBlocking(false); 
       chan.register(sel, SelectionKey.OP_READ); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

     if(key.isValid() && key.isReadable()) { 
      System.out.println("Read starting..."); 
      SocketChannel chan = (SocketChannel) key.channel(); 
      ByteBuffer buff = ByteBuffer.allocate(1024); 
      try { 
       while((chan.read(buff))>=0) { 
        buff.flip(); 
        System.out.println("read some"); 
        buff.clear(); 
       } 
       chan.close(); 
       System.out.println("Read complete"); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

客户:

static class Client implements Runnable { 
    @Override 
    public void run() { 
     try { 
      SocketChannel chan = SocketChannel.open(); 
      chan.connect(new InetSocketAddress("localhost", 5555)); 
      while(!chan.finishConnect()); 
      ByteBuffer buff = ByteBuffer.allocate(1024); 
      for(int i=0;i<1000;i++) { 
       buff.flip(); 
       chan.write(buff); 
       buff.compact(); 
      } 
      chan.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

以下是完整的源代码的pastebin。任何见解都会被赞赏

+1

它看起来不像你正在写任何数据。 (在启动服务器和客户端之间也存在竞争。) – 2012-02-17 17:34:40

+0

我试图写空字节。 IT部门仍然应该写数据?我尝试在启动客户端代码之前使用Thread.sleep(),但它没有帮助。 – bgroenks 2012-02-17 23:26:24

+1

但是你永远不会填满缓冲区。我想,调用“limit(int)'应该这样做。 (免责声明:我实际上没有做任何明智的NIO编程十年。) – 2012-02-18 01:18:39

回答

1

问题出在你的客户端,它不会写任何东西,正如汤姆所暗示的那样。 这里发生了什么:

ByteBuffer buff = ByteBuffer.alloacate(1024); // ==> position=0, limit=1024 

则:

buff.flip(); // ==> position=0, limit=0 

这是因为在javdaoc指定翻转()说:“限制设置为当前位置,然后将位置设置为零”。 所以,你需要至少一个模拟,你把一些数据到缓冲区,比如:

for(int i=0;i<1000;i++) { 
    buff.position(1024); // put 1024 bytes of data in the buffer 
    buff.flip(); 
    ... 
} 

此外,也不能保证chan.write()会写在一旦所有1024个字节,所以你可能想在循环中做到这一点:

for (int i=0;i<1000;i++) { 
    buf.position(1024); 
    buff.flip(); 
    while (buff.hasRemaining()) { 
    chan.write(buff); 
    buff.compact(); 
    } 
}