0

here is the important code:

public void setSelector() {
    try {

        this.writebuf.clear();
        this.selector = Selector.open();
        int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
        SelectionKey selectionKey = this.socketChannel.register(selector, interestSet);


        // Checking if the buffer is in write mode
        if (!(this.writebuf.limit() == this.writebuf.capacity())) {
            writebuf.flip();
        }

        int bytesRead = 0;

        while (selector.select() > -1) {

            // Wait for an event one of the registered channels

            // Iterate over the set of keys for which events are available
            Iterator selectedKeys = selector.selectedKeys().iterator();
            while (selectedKeys.hasNext()) {
                SelectionKey key = (SelectionKey) selectedKeys.next();
                selectedKeys.remove();
                if (!key.isValid()) {
                    continue;
                }
                if (key.isReadable()) {

                    bytesRead = this.socketChannel.read(this.writebuf);

                    if (bytesRead > 0 && writebuf.hasRemaining()) {
                        this.writebuf.flip();
                        this.parseSubtitleMessage(new String(writebuf.array(), charset));
                        this.writebuf.clear();
                        this.writebuf.flip();
                    }
                }
                if (key.isWritable()) {
                // Not yet implemented
                }
            }
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Socketchannel is set to nonblocking mode. The first problem is that the while loop creates huge workload. Basically I need something that would pause the code until the READ or WRITE event occurs. Another problematic part is this code:

this.parseSubtitleMessage(new String(writebuf.array(), charset));

I know that when I call the array() method I'll get the whole buffer including some forgotten bytes from the previous message, even though I call the clear method. I found a solution that uses a while cycle to iterate over single bytes until the buffer.hasRemaining() is set to false. But I don't know how to use the specified charset in this case.

Edit: I solved my "infinite loop" problem, here is the fixed code:

public void runSelector() {
    try {

        this.writebuf.clear();

        // Checking if the buffer is in write mode
        if (!(this.writebuf.limit() == this.writebuf.capacity())) {
            writebuf.flip();
        }

        this.selector = Selector.open();

        int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

        int bytesRead = 0;

        SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);

        while(true) {

            int readyChannels = selector.select();

            if(readyChannels == 0) continue;


            Set<SelectionKey> selectedKeys = selector.selectedKeys();

            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

            while(keyIterator.hasNext()) {

                SelectionKey key = keyIterator.next();

                if (!key.isValid()) {
                    continue;
                }

                // Check if there's something to write in the queue and change interestops apropriately.
                if (monitorObject.tosendIsEmpty()) {
                    selectionKey.interestOps(SelectionKey.OP_READ);
                } else {
                    selectionKey.interestOps(interestSet_RW);
                }

                if (key.isWritable()) {
                }

                if (key.isReadable()) {
                    bytesRead = this.socketChannel.read(this.writebuf);

                    if (bytesRead > 0 && writebuf.hasRemaining()) {
                        this.parseSubtitleMessage(new String(this.writebuf.array(), charset));
                        this.writebuf.clear();
                    }
                }
                keyIterator.remove();
            }
        }




    } catch (IOException e) {
        e.printStackTrace();
    }
}

I unintentionally created sligthly duplicate thread. My google skills were probably really bad that day. However the second problem still remains and I'll definitely appreciate your help. Thanks

Edit 2: So I fixed my second problem too. Here is the code:

                if (key.isReadable()) {

                    bytesRead = this.socketChannel.read(this.writebuf);

                    bytes = new byte[bytesRead];

                    int x = 0;

                    this.writebuf.flip();

                    while(this.writebuf.hasRemaining()) {
                        bytes[x] = this.writebuf.get();
                        x++;
                    }

                    System.out.println(new String(bytes, charset));

                    this.writebuf.flip();
                    this.writebuf.clear();
                }
Jan
  • 1
  • 2
  • Not related to the actual problem, but you might start with fixing the *unchecked* warnings that your code generates (e.g. `selectedKeys()` returns a generic set). That also removes the need to cast. – dhke Sep 08 '15 at 14:02
  • Do you really need to use NIO itself? You might want to take a look at Netty (http://netty.io/) which makes it all much easier. – Wim Deblauwe Sep 10 '15 at 10:04
  • I don't need to use NIO. I'm just new to Java and I didn't know of netty. I'l remember it for the next time. Thanks – Jan Sep 10 '15 at 11:32

1 Answers1

0

Here is the final solution:

public void runSelector() {
    try {

        this.writebuf.clear();

        // Checking if the buffer is in write mode
        if (!(this.writebuf.limit() == this.writebuf.capacity())) {
            writebuf.flip();
        }

        this.selector = Selector.open();

        int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

        int bytesRead = 0;

        byte[] bytes = null;

        SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);

        while(true) {

            int readyChannels = selector.select();

            if(readyChannels == 0) continue;


            Set<SelectionKey> selectedKeys = selector.selectedKeys();

            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

            while(keyIterator.hasNext()) {

                SelectionKey key = keyIterator.next();

                if (!key.isValid()) {
                    continue;
                }

                // Check if there's something to write in the queue and change interestops apropriately.
                if (monitorObject.tosendIsEmpty()) {
                    selectionKey.interestOps(SelectionKey.OP_READ);
                } else {
                    selectionKey.interestOps(interestSet_RW);
                }

                if (key.isWritable()) {
                }

                if (key.isReadable()) {

                    bytesRead = this.socketChannel.read(this.writebuf);

                    bytes = new byte[bytesRead];

                    int x = 0;

                    this.writebuf.flip();

                    while(this.writebuf.hasRemaining()) {
                        bytes[x] = this.writebuf.get();
                        x++;
                    }

                    System.out.println(new String(bytes, charset));

                    this.writebuf.flip();
                    this.writebuf.clear();
                }
                keyIterator.remove();
            }
        }




    } catch (IOException e) {
        e.printStackTrace();
    }
}
Jan
  • 1
  • 2