One thread one ByteBuffer NIO

161 views Asked by At

I am wondering about the best way to implement a multiuser NIO server with one thread and one buffer. Currently I use a selector to achieve this but I have only figured out how to do reading on all the clients. I am having trouble implementing write using the one buffer. Do I need a second buffer for writes? Or do I have to (unfortunately) have a write buffer per client? I wrote this example to easily show how I'm doing stuff, just so you know all processing happens within the scheduler's thread, I am not interacting with any state through another thread!

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

There are 1 answers

4
user207421 On BEST ANSWER

You can't. For anything less trivial than an echo server, you need at least one buffer per channel, possibly two (read and write). Otherwise you can't possibly deal with partially read requests, or partially written responses.

You can associate the buffers with the channel via the SelectionKey attachment.