如何使用 socketchannel 提高以下代码的性能?我怎样才能收到 UTF8 字符串?

How to improve the performance of the following code using socketchannel? And how can I receive UTF8 string?

这里是重要的代码:

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 设置为 nonblocking 模式。 第一个问题是 while 循环会产生巨大的工作量。基本上,我需要一些可以 pause 代码直到 READWRITE event 发生的东西。 另一个有问题的部分是这段代码:

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

我知道,当我调用 array() 方法时,我将获得整个缓冲区,其中包括前一条消息中的一些 forgotten 字节,即使我调用了 clear 方法。我找到了一个解决方案,它使用 while 循环迭代单个字节,直到 buffer.hasRemaining() 设置为 false。但是我不知道在这种情况下如何使用指定的字符集。

编辑: 我解决了我的 "infinite loop" 问题,这里是固定代码:

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

我无意中创建了稍微重复的线程。那天我的 google 技能可能真的很糟糕。 但是第二个问题仍然存在,我非常感谢您的帮助。谢谢

编辑 2:所以我也解决了第二个问题。这是代码:

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

这是最终的解决方案:

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