我目前正在使用Netty 4.0.7.Final来编写一个通过TCP接收图像(大小:~10k)的服务器。 我修改了Netty的示例echo客户端处理程序,只是将文件读入字节,并将其发送到我的Netty服务器。
public EchoClientHandler(int firstMessageSize) throws IOException {
File image = new File("google.jpeg");
byte[] imageBytes = FileUtils.readFileToByteArray(image);
byte[] bytes = Base64.encodeBase64(imageBytes);
String base64 = new String(bytes);
//System.out.println("base64="+ base64);
firstMessage = Unpooled.copiedBuffer(base64, CharsetUtil.UTF_8);
}
我的测试图像是9k,我可以看到整个图像是通过Netty日志记录发送的
io.netty.handler.logging.LoggingHandler logMessage
INFO: [id: 0x132baef0, /127.0.0.1:49710 => localhost/127.0.0.1:2112] WRITE(11964B)
然而,当Netty服务器收到消息时,它似乎将消息分成两个数据包,第一个数据包是1024个字节,第二个数据包是10940个字节,最多加起来为1024 + 10940 = 11964字节(图像的总大小)
2013-08-24 22:56:33,700 [nioEventLoopGroup-3-1] INFO MessageDecoder - capacity = 1024
2013-08-24 22:56:33,700 [nioEventLoopGroup-3-1] INFO MessageDecoder - readable bytes = 1024
2013-08-24 22:56:33,709 [nioEventLoopGroup-3-1] INFO MessageDecoder - capacity = 16384
2013-08-24 22:56:33,710 [nioEventLoopGroup-3-1] INFO MessageDecoder - readable bytes = 10940
这就是我的解码器的样子(虽然我怀疑解码器与它有什么关系,看起来Netty在它到达解码器之前就处理了这个)
public class MessageDecoder extends ByteToMessageDecoder {
private static final Logger LOGGER = LoggerFactory.getLogger(MessageDecoder.class);
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
// Convert to String first
LOGGER.info("capacity = " + in.capacity());
LOGGER.info("readable bytes = " + in.readableBytes());
String rawString = in.readBytes(in.readableBytes()).toString(CharsetUtil.UTF_8);
LOGGER.info("Received base64 String={}", rawString);
}
我也试过大量的文件,看起来Netty总是将一条消息分成1024字节的数据包+文件的其余部分是什么大小?
我想知道为什么Netty会这样做?有没有办法一次性获取完整的数据包?
非常感谢。
答案 0 :(得分:3)
如果您想从处理程序中抽象碎片,则需要构建消息框架。这可以通过在发送时使用LengthFieldPrepender
和在接收时使用LengthFieldBasedFrameDecoder
轻松完成。这可以确保您的消息解码器只能看到表示完整消息的字节缓冲区。
请注意,您的帧处理程序应该位于ChannelPipeline
中,除非您还使用SSL处理程序和/或压缩处理程序,在这种情况下,SSL应该是第一个,然后是压缩,然后是帧处理程序。成为管道中的第一个意味着处理程序将首先处理和入站事件,并最后处理出站事件。