【发布时间】:2020-01-13 09:25:59
【问题描述】:
自定义 ByteToMessageEncoder 不接收在同一 tcp 连接中但在不同 tcp 消息中发送的字节。
我被指派解决几年前的系统开始出现异常的问题。在我看来,其他一些开发人员用 netty 编写了一个 tcp 服务器,它接收具有静态长度标头和可变长度正文的二进制消息。正文长度由一个标头字段定义,该字段告诉消息类型。我们维护一个消息类型及其长度的映射。
面临的问题是,在正确解码标头并知道正文长度后,相同的解码器期望正文进入相同的 ByteBuf(即来自 byteChannel 的一个 fireChannelRead 事件)。
但是,有时缓冲区中没有足够的东西,所以解码器放弃了。但是下次调用 decode-method 时,body 字节会出现并被错误地解释为 header,从而使解码器不同步。
使用 netty 组装消息的正确方法是什么,其字节可能会以更小的块的形式出现?
这是当前解码器的基础知识。
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
Message message = decode(ctx, in);
if (message != null) {
out.add(message);
}
}
protected Message decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
if (in.readableBytes() < MessageHeader.SIZE) {
return null;
}
ByteBuf headerBytes = in.readBytes(MessageHeader.SIZE);
MessageHeader header = MessageHeader.decode(headerBytes, new ProcessingTracker(MessagePart.HEADER));
if (header == null) {
ctx.disconnect().sync();
logger.debug("Disconnected from channel");
return null;
}
int bodySize = header.getMessageType().getMessageBodySize();
if (!waitingForBytes(in, bodySize, READ_TRY_TIMES)) {
ctx.disconnect().sync();
logger.debug("Disconnected from channel");
return null;
}
ByteBuf messageBytes = in.readBytes(bodySize);
messageBytes.resetReaderIndex();
Message message = Message.decode(header, messageBytes, 0);
return message;
}
public boolean waitingForBytes(ByteBuf in, int bodySize, int counter) {
if (counter == 0) {
logger.warn("Didn't get enough bytes of message body in MessagDecoder. Giving up and disconnecting from remote peer.");
return false;
}
logger.debug(String.format("Readable bytes in buffer %d, expected %d", in.readableBytes(), bodySize));
if (in.readableBytes() < bodySize) {
try {
Thread.sleep(20L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return waitingForBytes(in, bodySize, counter - 1);
} else {
return true;
}
}
【问题讨论】: