Netty服务端如何检测Netty客户端的关闭行为?
Netty与原生Java NIO检测客户端断开的差异
当已连接的Netty客户端被强制关闭时,Netty服务端会检测到该关闭操作并抛出IOException:
java.io.IOException: 远程主机强迫关闭了一个现有的连接(In English: the remote host forcely closed an existing connection)。 at sun.nio.ch.SocketDispatcher.read0(Native Method) at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43) at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) at sun.nio.ch.IOUtil.read(IOUtil.java:192) at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:378) at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288) at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1108) at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:345) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)
但原生Java NIO服务端无法主动检测客户端的关闭操作,除非向已断开的连接发送消息。
以下是用于测试Java NIO客户端关闭操作的示例代码:当客户端关闭时,服务端已注册的Socket Channel不会关闭,其SelectionKey也不会被移除。
NIO服务端
仅接受连接并打印接收到的内容:
public class Server { public static void main(String[] args) throws IOException, InterruptedException { Selector selector = Selector.open(); ServerSocketChannel serverSocket = ServerSocketChannel.open(); serverSocket.bind(new InetSocketAddress("localhost", 5454)); serverSocket.configureBlocking(false); serverSocket.register(selector, SelectionKey.OP_ACCEPT); ByteBuffer buffer = ByteBuffer.allocate(16); while (true) { Thread.sleep(3000); selector.select(); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> iter = selectedKeys.iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); if (key.isAcceptable()) { SocketChannel client = serverSocket.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } if (key.isReadable()) { SocketChannel client = (SocketChannel) key.channel(); client.read(buffer); byte[] array = new byte[buffer.position()]; buffer.flip(); buffer.get(array); System.out.println(new String(array)); buffer.clear(); } iter.remove(); } } } }
NIO客户端
发送消息后关闭连接。无论客户端正常退出还是通过ctrl+c强制关闭,NIO服务端都不会感知到连接断开:
public class Client { public static void main(String[] args) throws IOException, InterruptedException { SocketChannel client = SocketChannel.open(new InetSocketAddress("localhost", 5454)); ByteBuffer buffer = ByteBuffer.wrap("hello world".getBytes()); client.write(buffer); buffer.clear(); Thread.sleep(5000); ByteBuffer buffer1 = ByteBuffer.wrap("hello world1".getBytes()); client.write(buffer1); client.close(); } }
内容的提问来源于stack exchange,提问作者Machi
相关产品推荐
相关产品推荐

