Почему клиент будет блокировать при непрерывном получении изображения с сервера с Netty? - PullRequest
0 голосов
/ 31 октября 2018

Я хочу показать удаленный рабочий стол на клиенте в режиме реального времени. Это значит, что сервер постоянно посылает скриншот, а клиент рисует изображение на панели одновременно. Сначала он работает хорошо, но через несколько минут клиент блокируется, а сервер работает нормально.

Класс 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. Но нет СООБЩЕНИЯ ОШИБКИ, даже если я переопределяю метод exceptionCaught в каждом ChannelHandler. Я также попробовал Memory Analyzer, но, похоже, ничего не помогло.

Пожалуйста, помогите мне найти основную причину.

Здесь запущен проект https://github.com/leisuredong/RemoteDesktop

1 Ответ

0 голосов
/ 31 октября 2018

Это потому, что сервер отправляет изображения слишком быстро, а клиент - медленно. В этом случае клиенту не хватит памяти из-за переполнения входящего буфера netty клиента.

Лучшим вариантом для серверного кода было бы ожидание подтверждения от клиента (в течение заданного периода времени) перед отправкой следующего сообщения. Клиент может отправить подтверждение, когда завершит обработку текущего сообщения.

...