Netty channelRead not getting full message

2019-09-10 10:15发布

问题:

Why doesn't channelRead() give me the full message I send to the server? Fragmentation sometimes occur when messages are getting above 140 bytes (Roughly, sometimes more and sometimes less). I'm using a TCP socket using the NioServerSocketChannel class.

I'm using 4.1.0.Beta5.

Isn't there a way to read the full message when it has arrived?

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);

And class TestServerHandler extends 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);
}

I need a way to get the full bytebuf / bytearray when it has fully arrived at the server and get notified of that so my application can respond in a correct way according to the data the client has send.

So in short: How can I prevent fragmentation and have the channelRead event output the whole message / bytebuf.

回答1:

The basic data type used by Netty is Channel Buffers or ByteBuf. This is simply a collection of bytes and nothing else. In your code you have simply used a custom handler to handle the raw incoming data. This is generally not a good practice. A very basic netty pipeline should look something like the following

So a pipeline consists of a decoder / encoder and then we have our custom handlers or logging handlers. We never really handle any raw data as is. TCP is a stream protocol. It does not identify when a specific packet ends and a new packet starts. Even if we send a very very large packet or say two individual packets, they will simply be treated as a set of bytes and when we try to read the raw set of bytes, fragmentation might happen.

So properly implement a channel pipeline which consists of a String decoder / encoder (whatever you need) and this problem will go away.



回答2:

TCP provides a stream of bytes, so you can't rely on receiving a complete message in one packet. You will need a handler in your pipeline that knows how your messages are framed. Netty provides some built-in handlers that you can adapt for your protocol. See Dealing with a Stream-based Transport in the Netty User Guide.



标签: java netty