在selector注册了读就绪监听之后,读就绪事件就一直触发。
NIO的读就绪触发条件应该是内核缓存区有数据才触发,现在是哪怕客户端不发送消息,读就绪事件也会触发。
public class Server {
public static void main(String[] args) throws Exception {
SocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(socketAddress);
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
// accept就绪
if (selectionKey.isAcceptable()) {
ServerSocketChannel serverSocket = (ServerSocketChannel) selectionKey.channel();
SocketChannel socketChannel = serverSocket.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
// 读就绪
if (selectionKey.isReadable()) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = socketChannel.read(buffer))!=-1) {
buffer.flip();
System.out.println(new String(buffer.array(),0,len));
buffer.clear();
}
System.out.println("读就绪");
}
iterator.remove();
}
}
}
}
客户端代码
public class Client {
public static void main(String[] args) throws Exception{
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8080));
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("你好,我来了".getBytes());
buffer.flip();
socketChannel.write(buffer);
socketChannel.shutdownOutput();
socketChannel.close();
}
}
(stackoverflow原话)If bytesRead < 0 you should close the channel or at least deregister OP_READ. Otherwise you will keep getting OP_READ over and over again to tell you about the EOS.
原因就在于断开连接后,为了让你知道连接已断开,所以会产生OP_READ事件。
当客户端的链接异常断开,此时代表这个链接的channel一直处于readable的状态,如何检查链接已断开呢?链接断开后,虽然该channel的ready operation是OP_READ,但是此时channel.read(buffer)返回-1,此时可以增加一个判断。