2015-06-15 39 views
0

我想知道用一個線程和一個緩衝區實現多用戶NIO服務器的最佳方法。目前我使用選擇器來實現這一點,但我只想到如何閱讀所有的客戶端。我在使用一個緩衝區實現寫入時遇到了問題。我是否需要第二個寫入緩衝區?或者我必須(不幸)每個客戶端都有一個寫緩衝區?我寫這個例子很容易展示我如何做事,只是爲了讓你知道所有的處理都發生在調度器的線程中,我不會通過另一個線程與任何狀態進行交互!One thread one ByteBuffer NIO

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); 

ServerSocketChannel server = ServerSocketChannel.open(); 
Selector selector = Selector.open(); 
ByteBuffer buffer = ByteBuffer.allocateDirect(8192); 
Map<SelectionKey, SocketChannel> clients = new HashMap<>(); 

server.configureBlocking(false); 
server.register(selector, SelectionKey.OP_ACCEPT); 
server.bind(new InetSocketAddress(43594)); 

scheduler.scheduleAtFixedRate(() -> { 
    try { 
     selector.selectNow(); 
     Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); 
     while (keys.hasNext()) { 
      SelectionKey key = keys.next(); 
      keys.remove(); 
      if (key.isAcceptable()) { 
       for (int i = 0; i < 16; i++) { 
        SocketChannel client = server.accept(); 
        if (client == null) 
         break; 
        client.configureBlocking(false); 
        SelectionKey clientKey = client.register(selector, SelectionKey.OP_READ); 
        clients.put(clientKey, client); 
       } 
      } 
      if (key.isReadable()) { 
       SocketChannel client = clients.get(key); 
       if (client != null) { 
        buffer.clear(); 
        client.read(buffer); 
        buffer.flip(); 
        // do stuff with buffer 
       } 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}, 600, 600, TimeUnit.MILLISECONDS); 

回答

1

你不能。對於比echo服務器小的任何東西,每個通道至少需要一個緩衝區,可能有兩個(讀取和寫入)。否則,你不可能處理部分讀取請求或部分寫入響應。

您可以通過SelectionKey附件將緩衝區與通道相關聯。

+0

您確定嗎?我目前的實現適用於許多客戶端,雖然我沒有處理部分讀取或寫入。你是否知道如何做到這一點的完整例子?我想在我的應用程序中最小化垃圾創建。 – Jire

+1

您當前的實現'工作'*是因爲*您尚未處理部分讀取或寫入操作。在你實現它的那一刻,你會意識到你需要每個通道有一個或兩個緩衝區來保存待處理數據。這當然很明顯?緩衝區或通道不會強加任何Gc負載,因爲它持續的時間與連接一樣長,在任何情況下,您的主要擔憂都必須是正確的。你可以在零時間得到錯誤的答案。這沒有關係或興趣。 – EJP

+0

謝謝你的迴應,它清理了一些東西。我想共享我的緩衝區以節省垃圾,有什麼建議嗎?另外我懷疑附件的效率。我意識到他們可以簡化我的代碼,並且可能(?)通過引入上下文來消除對我的客戶端映射的需求。雖然這款遊戲需要在少量硬件上運行數千個客戶端,但我並沒有進行實時開發。如果有幫助,系統基於每600毫秒發送一次消息。 – Jire