通过Netty发送TCP数据包,Netty将数据划分为不同的数据包?

时间:2013-08-24 15:17:54

标签: java sockets networking tcp netty

我目前正在使用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会这样做?有没有办法一次性获取完整的数据包?

非常感谢。

1 个答案:

答案 0 :(得分:3)

如果您想从处理程序中抽象碎片,则需要构建消息框架。这可以通过在发送时使用LengthFieldPrepender和在接收时使用LengthFieldBasedFrameDecoder轻松完成。这可以确保您的消息解码器只能看到表示完整消息的字节缓冲区。

请注意,您的帧处理程序应该位于ChannelPipeline中,除非您还使用SSL处理程序和/或压缩处理程序,在这种情况下,SSL应该是第一个,然后是压缩,然后是帧处理程序。成为管道中的第一个意味着处理程序将首先处理和入站事件,并最后处理出站事件。