【问题标题】:socket messages being split by netty套接字消息被 netty 拆分
【发布时间】:2014-05-29 19:35:35
【问题描述】:

我基于 netty 4 编写了一个 REST 服务器。客户端处理程序如下所示。

netty 提供的 msg 中的 bytebuffer 容量不同。当客户端消息大于缓冲区时,消息将被拆分。我发现每个片段都会调用 channelRead 和 ChannelReadComplete 。我通常看到的是 ByteBuf 在 512 左右,消息在 600 左右。我得到前 512 个字节的 channelRead,然后是 ChannelReadComplete ,然后是剩余 100 字节的另一个 channelRead 和他们的 channelReadComplete - 2 条消息而不是 1 条。

我在这里找到了一些相关的问题,但我想知道 channelReadComplete 有什么意义?它真的在每个 channelRead 之后调用吗?只要有可用的字节,难道不应该在调用 channelReadComplete 之前读入它们吗?

public class ClientHandler extends ChannelInboundHandlerAdapter {
    ....
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Report.debug("Read from client");
        ByteBuf buf = (ByteBuf) msg;
        String contents = buf.toString(io.netty.util.CharsetUtil.US_ASCII);
        ReferenceCountUtil.release(msg);

        ClientConnection client = ClientConnection.get(ctx);
        if (client != null) {
            client.messageText(contents);   // adds text to buffer
            return;
        }
        ((parse serial number from contents, process registration))
        ClientConnection.online(serialNumber, ctx);     // register success, create the client object
    }

    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ClientConnection client = ClientConnection.get(ctx);
        if (client == null) 
            Report.debug("completed read of message from unregistered client");
        else {
            Report.debug("completed read of message from client " + client.serialNumber());
            String contents = client.messageText();
            ... ((process message))
        }
    }
 }

【问题讨论】:

    标签: java netty


    【解决方案1】:

    是的,在管道中的每个 channelRead() 完成后调用 channelReadComplete()。如果 channelRead() 发生异常,则会跳转到方法 ecxeptionCaught()。

    因此,您应该将只希望在成功的 channelRead() 上执行的代码放入 channelReadComplete()。

    例如,我们的项目就是这样做的:

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // compute msg
        ctx.fireChannelRead(msg); //tells the next handler 
                                  //in pipeline (if existing) to read the channel
    }
    
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush("OK");
        ctx.fireChannelReadComplete();
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error(Message.RCV_ERROR, cause.getMessage());
        ctx.writeAndFlush(cause.getMessage());
        ctx.close();
    }
    

    如果客户收到不同于“OK”的内容,那么他​​不必发送其余内容。 如果您正在寻找在所有包裹到达后被调用的方法,那么:

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //close the writer that wrote the message to file (for example)
    }
    

    编辑:您也可以尝试发送更大的包裹。我认为消息大小由客户端控制。

    【讨论】:

      【解决方案2】:

      channelReadComplete 不会在每个 channelRead 之后调用。 netty 事件循环将从 NIO 套接字读取并触发多个 channelRead,直到没有更多数据要读取或者它应该放弃,然后触发 channelReadComplete。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-15
        • 2011-03-27
        • 2016-02-26
        • 2014-05-20
        • 1970-01-01
        • 2014-08-31
        • 1970-01-01
        相关资源
        最近更新 更多