2012-02-17 37 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(); 
    } 
}