写入通道后,Java Selector返回带有OP_READ的SelectionKey,而无需在无限循环中的数据

我的代码出了问题:我用Selector编写了简单的SocketChannel客户端,启动后成功从服务器读取消息(服务器发送事件).但是在写入socket(参见main方法)之后,选择器开始在infinyty循环中返回可读套接字,handleKey返回-1个字节readed,因此选择器所有时间都返回OP_READ SelectionKey而没有数据用于读取.
对不起我的英语不好.

谢谢.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class SelectorTest
{

    public SelectorTest() throws IOException {
        selector = Selector.open();
    }

    private void runSelector() {

        new Thread(new Runnable() {

            public void run()
            {

                alive = true;
                try {
                    while(alive) {
                        System.out.println("Selector started...");

                        selector.select();

                        Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();

                        while(keyIter.hasNext()) {

                            SelectionKey key = keyIter.next();

                            keyIter.remove();

                            handleKey(key);
                        }
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }).start();
    }

    private void handleKey(SelectionKey key) throws IOException {

        SocketChannel chan = (SocketChannel) key.channel();
        System.out.println("Processing selected...");

        if(key.isConnectable()) {
            System.out.println("Connecting ...");
            if(chan.finishConnect()) {
                key.interestOps(SelectionKey.OP_READ);
            } else {
                key.channel();
            }
        } else if(key.isReadable()) {
            System.out.println("Processing reading...");

            ByteBuffer buf = ByteBuffer.allocate(1024);
            int readedBytes = chan.read(buf);
            System.out.println("Readed: " + readedBytes);
            buf.flip();

            for(byte b : buf.array()) {
                System.out.print((char) b);
            }
        } else if(key.isWritable()) {
            System.out.println("Finishing writing...");

            key.interestOps(SelectionKey.OP_READ);
        }
    }

    public static void main(String[] args) throws IOException {

        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);
        channel.connect(new InetSocketAddress("t1.sis.lan", 6001));

        SelectorTest ds = new SelectorTest();
        ds.runSelector();

        channel.register(ds.selector, SelectionKey.OP_CONNECT);

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        for(;;) {

            String line = in.readLine();
            if(line==null) break;

            if(line.toLowerCase().equals("bye")) break;

            if (line.toLowerCase().equals("write")) {
                String command = "GET_STREAMS\r\n\0";

                ByteBuffer buf = ByteBuffer.allocate(1024);
                buf.put(command.getBytes());
                buf.flip();

                channel.write(buf);
            }

            System.out.println("echo: "+line); // is it alive check
        }

        ds.alive = false;
        ds.selector.wakeup();
        channel.close();
    }

    private Selector selector;
    private boolean alive;

}

解决方法:

read()在EOS返回-1,你完全忽略了它.当您获得EOS时,您必须关闭频道或至少取消注册对OP_READ的兴趣.否则,当你正在做的时候,你将永远得到另一个OP_READ和另一个-1.与上面的注释相反,read()在空读取时返回零.你可以忽略它,如果你只读isReadable(),你甚至不会看到它,除非你在循环中读取,但你不能忽略EOS.

上一篇:java – Selector.select()启动一个无限循环


下一篇:_004_Docker_修改 Docker 中 MySQL 容器的编码