![](/img/trans.png)
[英]Sending TCP packets via Netty, Netty is dividing the data into different packets?
[英]Netty ByteToMessageDecoder not receiving messages sent in different tcp packets
自定義ByteToMessageEncoder不會接收在相同tcp連接中但在不同tcp消息中發送的字節。
我被分配來解決一個問題,在該問題中,使用了兩年的舊系統開始出現異常。 在我這方面,有一些其他開發人員用netty編寫的tcp服務器,它接收帶有靜態長度標頭和可變長度主體的二進制消息。 正文長度由告訴消息類型的標頭字段定義。 我們維護消息類型及其長度的映射。
面臨的問題是,在正確解碼了標頭並知道主體長度之后,同一解碼器期望主體出現在同一ByteBuf中(這是來自byteChannel的一個fireChannelRead事件)。
但是,有時緩沖區中沒有足夠的內容,因此解碼器放棄了。 但是,下次將解碼方法稱為主體字節時,就會顯示主體字節並將其錯誤地解釋為標頭,從而使解碼器不同步。
使用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;
}
}
您的代碼中存在多個問題...
首先,不允許您在代碼中調用sync()
,因為這樣將“死鎖” EventLoop
。
其次,您不能在此處使用waitingForBytes
,因為它基本上會使EventLoop
上的所有其他IO EventLoop
,這意味着您將永遠不會繼續執行任何IO。 在像Netty這樣的框架中, EventLoop
不要阻塞EventLoop
線程,這一點很重要,因為這基本上會導致一切陳舊,並且不會取得任何進展。
查看超類ByteToMessageDecoder
,很明顯子類應該通過讀取的字節或解碼的消息數來傳達解碼進度。 我認為我從那里繼承此代碼的人錯過了這一點。
此實現通過了一些初步測試:
public class MessageDecoder extends ByteToMessageDecoder {
private static final Logger logger = LoggerFactory.getLogger(MessageDecoder.class);
private ByteBuf headBuf = Unpooled.buffer(MessageHeader.SIZE);
private MessageHeader header = null;
private ByteBuf bodyBuf;
private int bodylength = 0;
private int messageBytes = 0;
private final static int STATE_READ_HEADER = 1, STATE_READ_BODY = 2;
private int state = STATE_READ_HEADER;
@Override
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 {
int readBytes = 0;
logstate(in);
switch (state) {
case STATE_READ_HEADER:
if (in.readableBytes() <= MessageHeader.SIZE - messageBytes) {
readBytes = in.readableBytes();
} else {
readBytes = MessageHeader.SIZE - messageBytes;
}
headBuf.writeBytes(in, readBytes);
messageBytes += readBytes;
if (messageBytes == MessageHeader.SIZE) {
state = STATE_READ_BODY;
header = MessageHeader.decode(headBuf, new ProcessingTracker(MessagePart.HEADER));
bodylength = header.getMessageType().getMessageBodySize();
bodyBuf = Unpooled.buffer(bodylength);
}
break;
case STATE_READ_BODY:
if (in.readableBytes() <= bodylength - (messageBytes - MessageHeader.SIZE)) {
readBytes = in.readableBytes();
} else {
readBytes = bodylength - (messageBytes - MessageHeader.SIZE);
}
bodyBuf.writeBytes(in, readBytes);
messageBytes += readBytes;
if (messageBytes == MessageHeader.SIZE + bodylength) {
state = STATE_READ_HEADER;
Message message = Message.decode(header, bodyBuf, 0);
reset();
return message;
}
break;
}
return null;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.