写入通道后,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 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。

read()在读取EOF时返回-1。 定义:

 read() returns: The number of bytes read, possibly zero, or -1 if the channel has reached end-of-stream 

这意味着您应取消注册OP_READ的兴趣。