【问题标题】:Netty ByteToMessageDecoder runs more times than it has toNetty ByteToMessageDecoder 运行的次数超过了它必须的次数
【发布时间】:2016-03-06 23:19:42
【问题描述】:

我正在尝试使用 netty 编写一个简单的客户端服务器应用程序。 我遵循this 教程,特别是时间服务器模型和 POJO 模型。我的问题是 ByteToMessageDecoder :它运行的次数超过了它必须运行的次数,这意味着它在读取空 ByteBuf 时不会停止,而是再读取一次,并且由于某种原因,我无法理解,它找到了我的客户的上一条消息发送!我确定客户端只发送一次所述消息!

所以想法是这样的:一个简单的客户端服务器模型,其中客户端发送一个带有“hello world”消息的“DataPacket”,服务器用一个带有“ACK”的“DataPacket”响应。我正在使用 DataPacket 类型,因为将来我想在其中传递更多的东西,添加一个标题并构建一些更复杂的东西......但对于初学者来说,我需要看看我在这个中做错了什么......

错误:

可以看到Server正常启动,我的Client(Transceiver)发送消息,encoder激活并从DataPacket转换为ByteBuf,消息从Server发送和接收,Server的Decoder激活并转换它从 ByteBuf 到 DataPacket,然后服务器相应地处理它......它应该发送 ACK 并向后重复相同的内容,但这是出了问题,我不明白为什么。

我在这里阅读了一些帖子,并且已经尝试过 LengthFieldBasedFrameDecoder,但它不起作用,我还想看看这个有什么问题,如果可能的话,不要使用其他东西......

代码:

编码器和解码器类:

 package org.client_server;

import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.CharsetUtil;

public class EncoderDecoder {

    public static class NettyEncoder extends MessageToByteEncoder<DataPacket> {

        @Override
        protected void encode(ChannelHandlerContext ctx, DataPacket msg, ByteBuf out)
                throws Exception {
            System.out.println("Encode: "+msg.getData());
            out.writeBytes(msg.convertData());
        }       
    }

    public static class NettyDecoder extends ByteToMessageDecoder{

        @Override
        protected void decode(ChannelHandlerContext ctx, ByteBuf in,
                List<Object> out) throws Exception {
            if((in.readableBytes() < 4) ) {
                return;
            }
            String msg = in.toString(CharsetUtil.UTF_8);
            System.out.println("Decode:"+msg);

            out.add(new DataPacket(msg));
        }

    }

}

服务器处理程序:

class DataAvroHandler extends ChannelInboundHandlerAdapter {


        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg)
                throws Exception {
            try {
                DataPacket in = (DataPacket)msg;
                System.out.println("[Server]: Message received..."+in.getData());
            }finally {
                ReferenceCountUtil.release(msg);
                //ctx.close();
            }
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx)
                throws Exception {
            System.out.println("[Server]: Read Complete...");
            DataPacket pkt = new DataPacket("ACK!");
            //pkt.setData(Unpooled.copiedBuffer("ACK", CharsetUtil.UTF_8));
            ctx.writeAndFlush(pkt);         
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
                throws Exception {
            serverLog.warning("[Server]: Error..." + cause.toString());
            ctx.close();            
        }

客户端处理程序:

class DataAvroHandlerCl extends ChannelInboundHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        System.out.println("[Transceiver]: Channel Active!!!");
        DataPacket pkt = new DataPacket("Hello World!");
        ChannelFuture f = ctx.writeAndFlush(pkt);
        //f.addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            DataPacket in = (DataPacket)msg;
            System.out.println("[Transceiver]: Message received..."+in.getData());
        }finally {
            ReferenceCountUtil.release(msg);
            //ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        transLog.warning("[Transceiver] : Error..." + cause.getMessage());
        ctx.close();
    }

}

服务器和客户端管道:

ch.pipeline().addLast("Decoder", new EncoderDecoder.NettyDecoder());
ch.pipeline().addLast("Encoder", new EncoderDecoder.NettyEncoder());
ch.pipeline().addLast("DataAvroHandler", new DataAvroHandler());

【问题讨论】:

    标签: java server netty decode


    【解决方案1】:

    您的问题源于在您的NettyDecoder 中使用ByteBuf in 的toString() 方法。

    引用 javadoc (http://netty.io/4.0/api/io/netty/buffer/ByteBuf.html#toString%28java.nio.charset.Charset%29):

    此方法不会修改此缓冲区的 readerIndex 或 writerIndex。

    现在,ByteToMessageDecoder 不知道您实际解码了多少字节!看起来您解码了 0 个字节,因为缓冲区的 readerIndex 未修改,因此您还会在控制台中收到错误消息。

    您必须手动修改 readerIndex:

    String msg = in.toString(CharsetUtil.UTF_8);
    in.readerIndex(in.readerIndex() + in.readableBytes());
    System.out.println("Decode:"+msg);
    

    【讨论】:

    • 谢谢!它工作得很好!!作为记录,因为应该避免使用 toString() 什么是转换字符串的好方法?
    • 你可以使用 netty 自己的StringDecoder (netty.io/4.0/api/io/netty/handler/codec/string/…)。但是看一下实现,我看到它本身使用了toString(),所以这里看起来很合适!通常toString() 方法用于文本输出,性能并不高,我概括得太早了 - 抱歉。
    猜你喜欢
    • 1970-01-01
    • 2021-09-22
    • 2020-01-01
    • 2016-04-28
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    相关资源
    最近更新 更多