【问题标题】:Netty channelRead not getting full messageNetty channelRead 没有收到完整的消息
【发布时间】:2015-09-28 09:59:27
【问题描述】:

为什么 channelRead() 不给我发送到服务器的完整消息?当消息超过 140 字节(大致,有时更多有时更少)时,有时会发生碎片。我正在使用使用 NioServerSocketChannel 类的 TCP 套接字。

我使用的是 4.1.0.Beta5。

有没有办法在邮件到达时阅读完整的邮件?

this.serverBootstrap = new ServerBootstrap();
this.serverBootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup(6))
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>()
                {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception
                    {
                        ch.pipeline().addLast(new TestServerHandler());
                    }
                })
                .option(ChannelOption.SO_BACKLOG, (int)Short.MAX_VALUE)
                .option(ChannelOption.SO_RCVBUF, (int) Short.MAX_VALUE)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true);
this.serverBootstrap.bind(this.host, this.port);

TestServerHandler 类扩展了 ChannelInboundHandlerAdapter:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {

        String s = buffer.toString(CharsetUtil.UTF_8);

        for(int i = 0; i < 20; i++)
        {
            s = s.replace("[" + ((char)i) + "]", i + "");
        }

        System.out.println(s.length() + "");
        System.out.println();
        System.out.println();
        System.out.println(s);
}

我需要一种方法在它完全到达服务器时获取完整的 bytebuf / bytearray 并得到通知,以便我的应用程序可以根据客户端发送的数据以正确的方式响应。

简而言之:如何防止碎片化并让 channelRead 事件输出整个消息/字节缓冲区。

【问题讨论】:

  • 快速浏览一下代码我会说你没有对channelRead() 中的味精Object 做任何事情。

标签: java netty


【解决方案1】:

TCP 提供字节流,因此您不能依赖于在一个数据包中接收完整的消息。您将需要在您的管道中使用一个处理程序,该处理程序知道您的消息是如何构建的。 Netty 提供了一些内置的处理程序,您可以根据自己的协议进行调整。请参阅 Netty 用户指南中的 Dealing with a Stream-based Transport

【讨论】:

    【解决方案2】:

    Netty 使用的基本数据类型是 Channel Buffers 或 ByteBuf。这只是字节的集合,没有别的。在您的代码中,您只需使用自定义处理程序来处理原始传入数据。这通常不是一个好的做法。一个非常基本的 netty 管道应该如下所示

    因此,管道由解码器/编码器组成,然后我们有自定义处理程序或日志处理程序。我们从未真正按原样处理任何原始数据。 TCP 是一种流协议。它不识别特定数据包何时结束以及新数据包何时开始。即使我们发送一个非常大的数据包或者说两个单独的数据包,它们也会被简单地视为一组字节,当我们尝试读取原始字节集时,可能会发生碎片。 p>

    因此,正确实施由字符串解码器/编码器(无论您需要什么)组成的通道管道,这个问题就会消失。

    【讨论】:

    • 如果一个数据包被拆分成多个数据包/ByteBuf,由于客户端性质(我无法修改),我不知道什么属于什么。客户端将数据作为一个数据包发送,并且不进行拆分。假设两个长数据包在中间某处被拆分,我无法确定第二部分属于数据包。
    • @Wesley 这是真的。您不可能知道哪一组字节属于哪个数据包。一种可能的解决方案是您自己添加一些分隔符来标识数据包的结尾。但正如你所说,这是不可能的。但是,在这种情况下使用编码器时,Netty 会为您处理这些问题。您只需要发送数据包,当它穿过 Netty 管道并到达您的自定义处理程序时,它将是一个完整的数据包。
    • @Wesley 请参考这个 Git repo。 github.com/edorado93/StringDecoding
    • @Wesley 如果这对您有用,请接受答案,以便其他读者可以从中受益。 :)
    猜你喜欢
    • 1970-01-01
    • 2015-11-19
    • 2014-04-29
    • 2014-12-20
    • 2012-08-20
    • 2017-03-18
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    相关资源
    最近更新 更多