如何使用Netty同时发送命令与文件?解码异常及文件缺失问题求助
我现在遇到了一个Netty的问题:不清楚自己操作里的错误,想知道怎么用Netty同时发送命令和文件。先说说我的管道配置:
客户端管道配置
pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); //入站 pipeline.addLast(new ObjectEncoder()); //出站 pipeline.addLast(new ChunkedWriteHandler()); //出站 pipeline.addLast(new FileSenderHandler()); //入站(响应中写入) pipeline.addLast(new FileInfoSenderHandler()); //出站
服务端管道配置
pipeline.addLast(new ObjectEncoder()); //出站 pipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); //入站 pipeline.addLast(new FileReceiverHandler()); //入站 pipeline.addLast(new FileInfoReceiverHandler()); //入站(响应中写入)
我的操作逻辑是:发送文件前先发送FileInfo命令对象,告知服务端即将传输该命令描述的文件,随后发送文件本身(用ByteBuf)。但问题来了,ByteBuf也会经过ObjectDecoder,Java处理第一个数据块时直接抛出异常:
2021-10-09 01:26:02 WARN DefaultChannelPipeline:1152 - 触发了exceptionCaught()事件,且该事件已到达管道尾部。这通常意味着管道中的最后一个处理器未处理该异常。
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 4292411364 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:503)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:489)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.exceededFrameLength(LengthFieldBasedFrameDecoder.java:376)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:419)
at io.netty.handler.codec.serialization.ObjectDecoder.decode(ObjectDecoder.java:69)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:332)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
如果我重写decode()方法并添加日志,能看到文件传输没结束时,每个数据块都会经过ObjectDecoder并被解码为null,后续数据块倒是不会抛出异常。
已尝试的解决方法
- 在
ObjectDecoder构造方法里设置maxObjectSize = Integer.MAX_VALUE,但问题依然存在; - 重写
decode()方法添加条件判断:
结果文件会缺失2048字节;@Override protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { System.out.println("decode()"); Object o = super.decode(ctx, in); System.out.println(o); if(o == null){ System.out.println(in); return in; } return o; } - 通过代码动态修改管道(根据连接状态删除/添加
ObjectDecoder),服务端能正常接收文件,但我不确定这个方案是不是正确的。
我现在怀疑是不是自己的逻辑有根本性错误?已经查了几乎所有相关文档,耗了两周时间还是没解决。想问问我还需要学习哪些相关内容?恳请大家帮忙,谢谢!
内容的提问来源于stack exchange,提问作者Самый Важный

