Question

Hi I am trying to implements a simple Java NIO server; which registers the socketChannel with the selector. Hence I wish to listen to client and send some response back. After the socketChannel is registered with the selector, even if client(non NIO) sends some data, Server is not able to read; howerver the key generated is still being iterated.

Detailed View: Server Side:

**First thread**:

public void run() { while (true) {

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.configureBlocking(true);
    serverSocketChannel.socket().bind(inetAdressOfServer);
    SocketChannel clientChannel = serverSocketChannel.accept();
    new Listener("").addSocketChannel(clientChannel);

}}

**Second Thread**:

    static Selector selector = Selector.open();
    public boolean addSocketChannel(SocketChannel clientChannel) {

        SelectionKey key = clientSocketChannel.register(selector, selector.OP_READ|SelectionKey.OP_WRITE);              
        key.attach(new ChannelCallback(clientSocketChannel));
        return key.isValid();
    }

    public void run() {

        Set keysSet = selector.keys();
        Iterator i = keysSet.iterator();        
        while (i.hasNext()) {
            SelectionKey key = (SelectionKey) i.next();
        }

        if (key.isReadable()) {
            //read and do something
        }
    }



Client Side:

Socket socket = new Socket(serverIP, serverPort);    
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());    
dos.writeBytes(str + "\n");

NB: When done in single thread, the same program works, but when implemented in the manner mentioned above causes it not to listen to client. Please help me to resolve this issue.

Was it helpful?

Solution

It's very difficult to see what you have done there, but it looks as if what you have marked as "second thread" is used by both threads (some confusion over implementing Runnable/extending Thread and actual threads?). In particular, I'm guessing the new Listener constructs and starts a thread. You are then calling addSocketChannel in the first thread. Therefore, there is a race condition.

Also it's a poor idea to make selector static.

OTHER TIPS

Read works reading from another thread, here are the obvious problems with your code.

public void run() {
    Set keysSet = selector.keys();

Here you are taking the key set from the iterator, but there is no code ever doing select() or selectNow() on the selector, so this set will always be empty.

    Iterator i = keysSet.iterator();        
    while (i.hasNext()) {
        SelectionKey key = (SelectionKey) i.next();
    }
    if (key.isReadable()) {
        //read and do something
    }
}

This doesn't even compile, the check for 'read' on the key must be done inside the while-block.

SelectionKey key = clientSocketChannel.register(selector,
                                                SelectionKey.OP_READ | 
                                                SelectionKey.OP_WRITE);              

Two problems: The channel should be set in non-blocking mode before this is done and SelectionKey.OP_WRITE should not be set unless you want the key to be returned every time you run a select.

You should only set SelectionKey.OP_WRITE if you are actually planning to do a write.

Finally, using two threads here is very unconventional. The recommended way of doing this is to register the ServerSocketChannel to the Selector with OP_ACCEPT, and run the accept on the ServerSocket on the same thread as read/writes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top