Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java NIO SeletionKey迭代器和密钥处理,我做得对吗?_Java_Multithreading_Sockets_Nio - Fatal编程技术网

Java NIO SeletionKey迭代器和密钥处理,我做得对吗?

Java NIO SeletionKey迭代器和密钥处理,我做得对吗?,java,multithreading,sockets,nio,Java,Multithreading,Sockets,Nio,我正在关注JavaNIO。我找到了正确的java文件。我已经将代码调整为在单个端口而不是多个端口上操作,并将数据简单地输出到屏幕上,而不是将其回显到客户端 当我运行代码时,无论是我的版本还是上面超链接上的版本,都显示通道处理不当。我只是从我笔记本电脑风扇的声音中得出这个结论,在放置了几条快速的System.out.println()消息后,我设法缩小了问题的范围。起初我认为selector.select()方法由于某种原因没有阻塞,通道看起来是空的,但是while(hascantent)循环一直

我正在关注JavaNIO。我找到了正确的java文件。我已经将代码调整为在单个端口而不是多个端口上操作,并将数据简单地输出到屏幕上,而不是将其回显到客户端

当我运行代码时,无论是我的版本还是上面超链接上的版本,都显示通道处理不当。我只是从我笔记本电脑风扇的声音中得出这个结论,在放置了几条快速的
System.out.println()
消息后,我设法缩小了问题的范围。起初我认为
selector.select()
方法由于某种原因没有阻塞,通道看起来是空的,但是
while(hascantent)
循环一直在迭代

经过一番搜索,我发现可能是我没有正确地操作钥匙。当从通道读取数据后,我调整代码以取消while(iterator.hasNext())循环底部if语句中的SelectionKey

这似乎已经达到了目的,现在我收到一条消息,通知在通道关闭之前没有更多的字节可读取,总体上运行起来似乎更平稳

这是我到目前为止所做工作的代码,我对如何实现这一点的想法正确吗?我是否在正确的位置取消了钥匙

public class ServerRunnable implements Runnable {

    private int serverPort;
    private int queueLength;

    public ServerRunnable(int serverPort, int queueLength) {
        this.serverPort = serverPort;
        this.queueLength = queueLength;

    }

    private boolean running;
    private ServerSocketChannel serverSocketChannel;
    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    @Override
    public void run() {
        try {
            Selector selector = Selector.open();

            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(serverPort));
            System.out
                    .println("DeviceServerV0.2 - Going to Listen for connections on port: "
                            + serverSocket.getLocalPort());
            running = true;

            SelectionKey serverAcceptKey = serverSocketChannel.register(
                    selector, SelectionKey.OP_ACCEPT);
            int count = 0;
            while (running) {
                int keyCount = selector.select();
                System.out.println("keyCount: " + keyCount);
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator keyIterator = selectedKeys.iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey key = (SelectionKey) keyIterator.next();

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

                        ServerSocketChannel ssc = (ServerSocketChannel) key
                                .channel();
                        SocketChannel sc = ssc.accept();
                        sc.configureBlocking(false);

                        // Here we add the new connection to the selector
                        SelectionKey newKey = sc.register(selector,
                                SelectionKey.OP_READ);

                        keyIterator.remove();

                    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
                        SocketChannel sc = (SocketChannel) key.channel();

                        // Going with this from the tutorial for now.
                        // TODO: Implement proper boolean controls here
                        while (true) {
                            buffer.clear();

                            int read = sc.read(buffer);

                            if (read <= 0) {
                                // System.out.println("Bytes read: " + read);
                                System.out
                                        .println("No more bytes, breaking loop.");

                                break;
                            } else {

                                buffer.flip();
                                String result = new String(buffer.array());
                                System.out
                                        .println("Buffer Contents: " + result);

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

                    }

                }

            }

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

    }

}
public类ServerRunnable实现Runnable{
专用int服务器端口;
私有整数队列长度;
public ServerRunnable(int serverPort,int queueLength){
this.serverPort=serverPort;
this.queueLength=队列长度;
}
私有布尔运行;
专用服务器socketchannel服务器socketchannel;
私有ByteBuffer缓冲区=ByteBuffer.allocate(1024);
@凌驾
公开募捐{
试一试{
选择器=选择器。打开();
serverSocketChannel=serverSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket ServerSocket=serverSocketChannel.socket();
bind(新的InetSocketAddress(serverPort));
系统输出
.println(“DeviceServerV0.2-将侦听端口上的连接:”
+serverSocket.getLocalPort());
运行=真;
SelectionKey serverAcceptKey=serverSocketChannel.register(
选择器,SelectionKey.OP_ACCEPT);
整数计数=0;
(跑步时){
int keyCount=selector.select();
System.out.println(“keyCount:+keyCount”);
设置selectedKeys=选择器。selectedKeys();
迭代器keyIterator=selectedKeys.Iterator();
while(keyIterator.hasNext()){
SelectionKey=(SelectionKey)keyIterator.next();
if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
ServerSocketChannel ssc=(ServerSocketChannel)键
.channel();
SocketChannel sc=ssc.accept();
sc.configureBlocking(假);
//在这里,我们将新连接添加到选择器
SelectionKey newKey=sc.寄存器(选择器,
选择键。操作(读取);
keyterator.remove();
}else if((key.readyOps()&SelectionKey.OP\u READ)==SelectionKey.OP\u READ){
SocketChannel sc=(SocketChannel)key.channel();
//现在,请继续本教程中的内容。
//TODO:在此处实现适当的布尔控件
while(true){
buffer.clear();
int read=sc.read(缓冲区);

当频道的
readyOps()
包含
SelectionKey.OP\u read
时,如果(读取),则意味着某些数据可以读取,而不是说频道可以完全读取到其末端。但这是您在
while(true)
循环中所做的;您正在读取并因此轮询频道,直到到达其末端为止


正确的处理方法是读取一次,不要尝试再次读取,除非下一个
选择
报告有更多数据要读取。

好的,谢谢!我已取出
while(true)
循环,并将
键移动到
if()中(阅读很棒!非常感谢你的帮助,我觉得我终于掌握了这一点。如果你不介意的话,最后一个问题是——当我阅读频道的数据时,我将密切关注“消息的结尾”标记,此时我需要响应。在收到该标记时立即响应是一种好的做法,还是应该设置写入操作的位,让选择器决定何时处理写入操作。请记住,最终我希望此系统使用线程池进行处理。我甚至不确定是否询问ri这里有一个问题,很抱歉,如果是在第一次写入通道时,缓冲区应该是空的,因此您可以简单地启动写入。但是,将第一次写入与所有其他写入一样处理,也就是说,等待通道准备好写入,让一段代码唯一地处理所有写入操作离子。谢谢你!你帮了我很大的忙,我现在对这一点有了更好的理解。它确实会带来伤害。它会增加开销。或者你必须一直注册OP_写入,这会导致大部分时间占用CPU,或者你必须注册OP_写入并等待下一次选择迭代,直到你可以写入为止,这会增加延迟。不管是哪种方式它的开销太大,而且完全没有必要。正确的方法是编写