当客户端连接关闭时,服务器select()不会阻塞,然后一直分发读就绪操作。
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 配置为非阻塞
serverSocketChannel.configureBlocking(false);
ServerSocket socket = serverSocketChannel.socket();
socket.bind(new InetSocketAddress(8899));
Selector selector = Selector.open();
// 将 serverSocketChannel 注册到Selector 上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
try {
// 在此阻塞监听,当 OP_ACCEPT 发生时,返回关注的事件的数量
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
selectionKeys.forEach(selectionKey -> {
final SocketChannel client;
try {
if (selectionKey.isAcceptable()) {
ServerSocketChannel channel = (ServerSocketChannel) selectionKey.channel();
client = channel.accept();
client.configureBlocking(false);
// serverSocketChannel是关注连接这个事件,SocketChannel是关注读取这个事件
client.register(selector, SelectionKey.OP_READ);
String key = UUID.randomUUID().toString();
clientMap.put(key, client);
} else if (selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = 0;
try {
count = client.read(buffer);
} catch (IOException e) {
// 客户端断开后,需要手动关闭channel
client.close();
// e.printStackTrace();
}
if (count > 0) {
buffer.flip();
// 将读到的数据编码
Charset charset = Charset.forName("utf-8");
String receiveMessage = String.valueOf(charset.decode(buffer).array());
System.out.println(client + ":" + receiveMessage);
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
// 清除
selectionKeys.clear();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
当客户端断开连接后,client.read(buffer);会出现异常,所以需要手动的关闭这个长链接。
参考
http://www.debugease.com/j2se/174167.html
https://blog.csdn.net/u011277203/article/details/9223545