2015-06-15 2 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

Вы не можете. Для любого менее тривиального, чем эхо-сервер, вам нужен хотя бы один буфер на канал, возможно, два (чтение и запись). В противном случае вы не сможете обрабатывать частично прочитанные запросы или частично написанные ответы.

Вы можете связать буферы с каналом через вложение SelectionKey.

+0

Уверены ли вы в этом? Моя текущая реализация работает для многих клиентов, хотя я не обрабатывал частичные чтения или записи. Есть ли какие-либо подробные примеры, которые вы знаете о том, как это сделать? Я хочу свести к минимуму создание мусора в своем приложении. – Jire

+1

Ваша текущая реализация «работает» *, потому что * вы не обрабатывали частичные чтения или записи. В тот момент, когда вы идете реализовать это, вы поймете, что вам нужен буфер или два на канал для хранения ожидающих данных. Неужели это очевидно? Буфер или канал не накладывают никакой нагрузки на Gc, поскольку он длится до тех пор, пока соединение, и в любом случае ваша главная проблема должна быть правильной. Вы можете получить неправильный ответ в нулевое время. Это не имеет никакого значения или интереса. – EJP

+0

Благодарим вас за ответ, он прояснил ситуацию. Я хочу объединить мои буферы, чтобы сэкономить на мусоре, какие-нибудь предложения там? Также я сомневаюсь в эффективности приложений. Я понимаю, что они могут упростить мой код и, возможно, (?) Удалить необходимость моей карты клиентов, введя контекст. Я не занимаюсь разработкой в ​​режиме реального времени, хотя для игры необходимо запустить тысячи клиентов на небольшом количестве аппаратных средств. Система основана на сообщениях, отправляемых каждые 600 мс, если это помогает! – Jire