繁体   English   中英

NIO选择器线程,按预期处理通道,但如何确保通道在使用后正确关闭?

[英]NIO Selector Thread, handling channels as expected, but how do I ensure channels are correctly closed after use?

所以我在ServerRunnable类中有以下代码:

public class FirmwareServerRunnable implements Runnable {

    private static Logger log = Logger.getLogger(FirmwareServerRunnable.class
            .getName());
    private LinkedTransferQueue<CommunicationState> communicationQueue;
    private int serverPort = 48485;

    public FirmwareServerRunnable(int port,
            LinkedTransferQueue<CommunicationState> communicationQueue) {
        serverPort = port;
        this.communicationQueue = communicationQueue;
    }

    private boolean running;
    private ServerSocketChannel serverSocketChannel;

    @Override
    public void run() {

        try {

            Selector selector = Selector.open();
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(serverPort));

            log.info("Selector Thread: FirmwareServer Runnable- Listening for connections on port: "
                    + serverSocket.getLocalPort());

            running = true;

            @SuppressWarnings("unused")
            SelectionKey serverAcceptKey = serverSocketChannel.register(
                    selector, SelectionKey.OP_ACCEPT);

            while (running) {

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

                while (keyIterator.hasNext()) {

                    SelectionKey key = (SelectionKey) keyIterator.next();

                    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {

                        acceptConnection(selector, key);
                        keyIterator.remove();

                    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
                        CommunicationState commsState = (CommunicationState) key
                                .attachment();
                        if (commsState.getCurrentState() == CommunicationState.STATE_READ) {
                            readFromSocketChannel(key);
                            keyIterator.remove();
                        }
                    } else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {

                        CommunicationState commsState = (CommunicationState) key
                                .attachment();
                        if (commsState.getCurrentState() == CommunicationState.STATE_WRITE) {


                            writeToSocketChannel(key);
                            keyIterator.remove();
                        }
                    }

                }

            }

        } catch (IOException e) {
            log.error(
                    "Firmware Selector Thread: An IOException occurred",
                    e);     
        }

    }

我的acceptConnection()方法接受一个连接,并向它添加一个CommunicationState对象(一个状态机),它包含ByteBuffer ,当前通道状态,客户端当前在通信过程中等等...
此服务器在进程中间切换通信方法。 最初它使用JSON消息与客户端进行通信,但是当它到达某一点时,它开始使用USART协议命令使用新固件刷新客户端。

完成此过程后,客户端将断开连接并重新启动。 这使我的频道处于未知状态。 我不确定该频道是否已经关闭。 我怎么检查这个? 我是否认为selector.selectedKeys()只返回准备好操作的键? 如果是这种情况,我该如何检查未正确关闭的连接? while(running){}循环中,我可以在此ServerRunnable中执行此操作吗?

我一直在考虑的一个选项是将一个对密钥本身的引用附加到CommunicationState机器上,然后我可以在进程完成后获得对该通道的引用并在那里关闭它。 但由于某种原因,我对这个解决方案感到不安,对我来说感觉不对。

如果包含甚至关闭的频道密钥,我可以使用key.isValid()来确认密钥是否需要永久删除?

我很感激你对这个过程的任何想法,我必须忽视一些事情。

编辑:快速测试似乎表明,所选键集中不包含通道键,除非它们已准备好进行三个定义的操作之一我的测试很糟糕。

已被对等方关闭的连接将导致选择器将您的频道视为可读,当您从中读取时,您将获得-1,因此您应关闭该频道,这将取消其选择键。

编辑

如果包含甚至关闭的频道密钥,我可以使用key.isValid()来确认密钥是否需要永久删除?

如果您关闭了频道,其键将被取消,因此您下次在选定键集中将看不到它。 如果对等方关闭了连接,请参见上文。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM