Java Netty ByteToMessageDecoder的运行次数超过了它必须运行的次数
我正在尝试使用netty编写一个简单的客户机-服务器应用程序。 我遵循了教程,特别是时间服务器模型和POJO模型。我的问题是ByteToMessageDecoder:它运行的次数超过了它必须运行的次数,这意味着当它读取空ByteBuf时,它不会停止,而是再次读取一次,并且由于某种原因,我无法理解,它会找到我的客户机发送的上一条消息!我确信客户只发送上述信息一次 其思想是这样的:一个简单的客户机-服务器模型,其中客户机发送一个包含“hello world”消息的“数据包”,服务器用一个带有“ACK”的“数据包”进行响应。我使用DataPacket类型是因为将来我想在其中传递更多的东西,添加一个头并构建一些更复杂的东西…但是对于初学者,我需要看看我在这方面做错了什么 错误: 如您所见,服务器正常启动,我的客户端(收发器)发送消息,编码器激活并将其从数据包转换为ByteBuf,消息从服务器发送和接收,来自服务器的解码器激活并将其从ByteBuf转换为数据包,然后服务器相应地处理它。。。它应该发送ACK并向后重复相同的操作,但如果出现问题,我无法理解原因 我在这里读过一些帖子,并且已经尝试了一个基于LengthField的帧解码器,它不起作用,如果可能的话,我也想看看这个有什么问题,不要使用其他东西 代码: 编码器和解码器类:Java Netty ByteToMessageDecoder的运行次数超过了它必须运行的次数,java,server,netty,decode,Java,Server,Netty,Decode,我正在尝试使用netty编写一个简单的客户机-服务器应用程序。 我遵循了教程,特别是时间服务器模型和POJO模型。我的问题是ByteToMessageDecoder:它运行的次数超过了它必须运行的次数,这意味着当它读取空ByteBuf时,它不会停止,而是再次读取一次,并且由于某种原因,我无法理解,它会找到我的客户机发送的上一条消息!我确信客户只发送上述信息一次 其思想是这样的:一个简单的客户机-服务器模型,其中客户机发送一个包含“hello world”消息的“数据包”,服务器用一个带有“ACK
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());
您的问题源于在
NettyDecoder
中使用ByteBuf的toString()
方法
引用javadoc():
此方法不修改此缓冲区的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
()。但是看一下实现,我发现它使用的是toString()
本身,所以在这里似乎是合适的!通常toString()
方法是用于文本输出的,并没有真正的性能,我总结得太早了-我道歉。