为什么客户端在使用 Netty 从服务器不断获取图像时会阻塞?

Why the client will block while fetching image continually from server with Netty?

我想在客户端实时显示远程桌面。即服务器不断发送屏幕截图,客户端同时在面板上绘制图像。一开始还好,几分钟后客户端会阻塞,服务器正常。

为屏幕截图定义的class CaptureImage。它有两个属性,长度和内容。

private int length;// The length of attribute content
private byte[] content;// The BufferedImage convert to bytearray

服务器主要代码:

public class ServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        BufferedImage image;
        Robot robot = new Robot();
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Rectangle rect = new Rectangle(0, 0, toolkit.getScreenSize().width, toolkit.getScreenSize().height);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        CaptureImage captureImage = new CaptureImage();
        while (true) {
            image = robot.createScreenCapture(rect);
            ImageIO.write(image, "jpg", baos);
            captureImage.setLength(baos.toByteArray().length);
            captureImage.setContent(baos.toByteArray());
            ctx.writeAndFlush(captureImage);// Deliver to ImageEncoder before writing
            Thread.sleep(100);
            baos.reset();
            // Always print if add System.out.println() here...
        }
    }
}

public class ImageEncoder extends MessageToByteEncoder<CaptureImage> {
    @Override
    protected void encode(ChannelHandlerContext ctx, CaptureImage msg, ByteBuf out) throws Exception {
        out.writeInt(msg.getLength());
        out.writeBytes(msg.getContent());
    }
}

客户端主要代码:

public class ClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // Accept msg from ImageDecoder
        CaptureImage captureImage = (CaptureImage) msg;
        RemoteDesktop.panel.display(captureImage.getContent());// Paint the image on the panel
    }
}

public class ImageDecoder extends ReplayingDecoder<Void> {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int length = in.readInt();

        byte[] content = new byte[length];
        in.readBytes(content);

        CaptureImage captureImage = new CaptureImage();
        captureImage.setLength(length);
        captureImage.setContent(content);

        out.add(captureImage);
        // The print will stop after a few minutes if add System.out.println() here...
    }
}

ServerHandler 中的打印一直在进行,但 ImageDecoder 中的打印可能会在几分钟后停止。

我遇到的问题看起来像OutOfMemoryError。但是,即使我在每个 ChannelHandler 中重写 exceptionCaught 方法,也没有任何错误消息。我也试过内存分析器,但似乎没有帮助。

请帮我找出关键原因。

可运行的项目在这里https://github.com/leisuredong/RemoteDesktop

这是因为服务器发送图片速度太快,而客户端速度太慢。在这种情况下,由于客户端的入站网络缓冲区已满,客户端将内存不足。

服务器代码的更好设计是在发送下一条消息之前等待来自客户端的确认(在给定时间段内)。客户端可以在处理完当前消息后发送确认。