You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:20:37