bgroenks
bgroenks

Reputation: 1889

How to use NIO Selectors correctly?

I'm having an issue with using Selectors.

I wrote some test code to try creating a Client/Server connection with a Selector on the Server end to manage the channels. The problem is that when the Selector selects the channel to read from and the read operation is processed, no data is actually read.

I posted this question on another forum and have not yet received any answers.

Server:

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();
            }
        }
    }
}

Client:

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();
        }
    }
}

Here is a pastebin of the full source code. Any insights appreciated.

Upvotes: 1

Views: 2743

Answers (1)

Lolo
Lolo

Reputation: 4357

The problem is in your client, which doesn't write anything, as hinted by Tom. here's what happens:

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

then:

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

This is as specified in the javdaoc for flip() : "The limit is set to the current position and then the position is set to zero". So you need to a least simulate that you put some data into the buffer, for instance:

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

Additionally, there is no guarantee that chan.write() will write all 1024 bytes at once, so you might want to do that in a loop:

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

Upvotes: 1

Related Questions