java netty ChannelInboundHandlerAdapter以约1500字节的速度剪切帧
我已经使用netty框架实现了一个服务器应用程序,它使用ChannelInblundHandlerAdapter读取传入字节
如标题所示,我的问题是,我不定期地从客户端获取内容,我想是的,这些内容在约1.500字节后被剪切。例如:在这种情况下,我应该收到一个大的JSON数组。因为它被切割了,我无法解析它
在使用消息之前,我尝试使用管道中的附加ByteToMessageDecoder通道对消息进行解码。但这并不能解决问题。我在JSON中没有分隔符,我可以检查并再次将两个(或更多)部分粘在一起
以下是我的管道配置:
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new IdleStateHandler(45,0,0));
ch.pipeline().addLast(new MyByteToMessageDecoder());
ch.pipeline().addLast(new GatewayCommunicationHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.option(ChannelOption.SO_RCVBUF, 8192)
.childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(8192))
.childOption(ChannelOption.SO_KEEPALIVE, true);
initRestServer();
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(Config.gatewayPort).sync();
f.channel().closeFuture().sync();
这就是我的ByteToMessageDecoder:(我知道它很乱,但我不知道在我的情况下如何处理它)
public class MyByteToMessageDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
byte[] receivedBytes = new byte[in.readableBytes()];
in.getBytes(in.readerIndex(), receivedBytes);
if (receivedBytes[in.readableBytes()-1] != (byte) 0) {
out.add(receivedBytes);
return;
}
int lenForOutBytes = 0;
for (Object o : out) {
byte[] bytes = (byte[]) o;
lenForOutBytes += bytes.length;
}
byte[] outBytes = new byte[lenForOutBytes];
for (Object o : out) {
byte[] bytes = (byte[]) o;
if (out.size() == 1) {
outBytes = (byte[]) out.get(0);
}
else {
int i = 0;
for (int j = 0; j < bytes.length; j++) {
outBytes[i + j] = bytes[j];
}
i += bytes.length;
}
}
ctx.fireChannelRead(outBytes);
in.resetReaderIndex();
}
...
还有其他人有这样的问题吗
谢谢你的回复
比尔·乔
# 1 楼答案
之所以会出现这个问题,是因为TCP是基于流的,而不是基于数据包的
这基本上发生了:
所以解决这个问题有多种方法
用长度预先结束邮件:
虽然这通常是解决数据包问题的最简单方法,但在同时处理大小消息时,它也是效率最低的方法。这也需要改变协议
其基本思想是在发送数据包之前预先设定长度,这样可以正确分割消息
优势
缺点
怎么做
如果使用标准整型字段,这非常简单,因为Netty为其内置了类:
这在管道中以以下方式使用
这基本上是按照如下方式对数据包进行帧处理:
您发送:
^{} 将其转换为:
然后,当您收到消息时,^{} 将其解码为:
在简单分隔符上拆分消息
有些协议采用不同的方法,而不是按固定长度拆分,而是按分隔符拆分。快速查看的方法是,Java中的字符串以
"
结尾,文本文件中的行以换行符结尾,自然文本中的段落以双换行符结尾优势
缺点
怎么做
当从Netty发送消息时,需要手动将分隔符添加到消息本身,当接收到消息时,可以使用^{} 将传入流解码为消息
管道示例:
这在管道中以以下方式使用
发送消息时,需要手动添加分隔符:
接收消息时,^{} 将消息转换为帧:
基于复杂业务分隔符的拆分
并不是所有的框架都很容易,如果避免的话,有些解决方案实际上是最好的,但有时,你真的需要做一些肮脏的工作
优势
缺点
这分为两类:
基于现有解码器
有了这些解决方案,您基本上可以使用来自其他框架的现有解码器来解析数据包,并检测数据包处理中的故障
以GSON和^{} 为例:
模式检测
如果要使用模式检测方法,需要了解协议。让我们为JSON制作一个模式检测解码器
基于JSON的结构,让我们做以下假设:
{
和}
以及[
和]
的匹配对"
之间应忽略{
和}
的匹配对\
时,{\
,则应忽略\
基于这些属性,让我们根据以下假设进行^{} :
接收消息时,它是这样工作的:
如您所见,我们收到了2条消息,其中1条甚至在2个“虚拟TCP”数据包之间被分割,这被我们的“JSON解码器”转换为以下字节码数据包: