我写了一个Decoder,它扩展了ByteToMessageDecoder。基本上,我想做的只是抛出异常(我假设DecoderException),如果我收到了不期望的消息,停止解码消息并关闭连接。
当我抛出一个异常时,会在下面的处理程序中捕获它,它将只记录它并关闭连接。而且我可以看到它正在发生,但随后又出现了问题......
由于某种原因,我得到另一条消息(相同的消息),直接进入解码器,解码器尝试再次解码它,但从下一个readerIndex开始,再次获得意外消息并以同样的原因抛出异常。
为什么我在管道中得到另一条相同的消息,而连接是关闭的?
如何防止这种情况发生?
public class Decoder extends ByteToMessageDecoder
{
private static Logger LOG = LoggerFactory.getLogger(Decoder.class);
private Codec codec;
private int contentSize = 0;
/**
* @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception
{
if (!buffer.isReadable())
return;
// read header
if (contentSize == 0) {
int id = buffer.readInt();
if (id == -1) {
LOG.warn("Received null message");
throw new DecoderException("Null message has been received.");
}
codec = CodecRegistry.getInstance().getCodec(id);
if (codec == null) {
LOG.error("No codec found for id: " + id);
throw new DecoderException("No codec found for id: " + id);
}
contentSize = buffer.readInt();
}
if (buffer.readableBytes() < contentSize) {
return;
}
// read content
ByteBufInputStream bbis = new ByteBufInputStream(buffer);
out.add(codec.decode(bbis));
contentSize = 0;
}
}
@Sharable
public class ClientHandler extends ChannelHandlerAdapter
{
private static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
/**
* @see io.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
LOG.info("I got the message!!! -> " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
LOG.error("Unexpected exception from downstream." + cause);
ctx.close();
}
}
public class ClientInitializer extends ChannelInitializer<SocketChannel>
{
/**
* @see io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.Channel)
*/
@Override
protected void initChannel(SocketChannel ch) throws Exception
{
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new Decoder());
pipeline.addLast("encoder", new Encoder());
// and then business logic.
pipeline.addLast("handler", new ClientHandler());
}
}
服务器发送的消息只包含8个字节:
buffer.writeInt(-1);
buffer.writeInt(12345);
所以我希望DecoderException("Null message has been received.");
我在日志中看到的是:
INFO main Client - Starting Client.......... WARN nioEventLoopGroup-2-1 Decoder - Received null message ERROR nioEventLoopGroup-2-1 ClientHandler - Unexpected exception from downstream.io.netty.handler.codec.DecoderException: org.jasypt.contrib.org.apache.commons.codec_1_3.DecoderException: Null message has been received. INFO nioEventLoopGroup-2-1 Client - Disconnected from the server. ERROR nioEventLoopGroup-2-1 Decoder - No codec found for id: 12345 ERROR nioEventLoopGroup-2-1 ClientHandler - Unexpected exception from downstream.io.netty.handler.codec.DecoderException: org.jasypt.contrib.org.apache.commons.codec_1_3.DecoderException: No codec found for id: 12345
答案 0 :(得分:1)
在尝试解码标头之前,必须确保缓冲区的字节数超过8个字节。如果我是你,我会这样做:
// read header
if (contentSize == 0) {
if (buffer.readableBytes() < 8) {
return;
}
int id = buffer.readInt();
...