Netty 为什么在使用MessageToByteEncoder时需要调用ctx.writeAndFlush

Netty 为什么在使用MessageToByteEncoder时需要调用ctx.writeAndFlush,netty,Netty,我在Netty上实现了SIP服务器,使用Netty 3.x一切正常。然而,由于定义良好的线程模型,我决定升级到Netty 4,但情况发生了很大变化,我迷路了。我最初的问题是关于MessageToByteEncoder以及为什么我必须自己调用ctx.writeAndFlush,我的问题(我已经让它大部分工作正常了,但我现在还不太明白) 引导程序: private void createTCPListeningPoint() { this.serverBootstrap = new Serv

我在Netty上实现了SIP服务器,使用Netty 3.x一切正常。然而,由于定义良好的线程模型,我决定升级到Netty 4,但情况发生了很大变化,我迷路了。我最初的问题是关于
MessageToByteEncoder
以及为什么我必须自己调用
ctx.writeAndFlush
,我的问题(我已经让它大部分工作正常了,但我现在还不太明白)

引导程序:

private void createTCPListeningPoint() {
    this.serverBootstrap = new ServerBootstrap();

    this.serverBootstrap.group(this.bossGroup, this.workerGroup)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(final SocketChannel ch) throws Exception {
                    final ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast("decoder", new SipFrameDecoder(Protocol.TCP));
                    pipeline.addLast("encoder", new SipMessageEncoder());
                    pipeline.addLast("handler", NettyNetworkStack.this.sipHandler);
                }
            });
    // .option(ChannelOption.SO_BACKLOG, 128)
    // .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
    // .childOption(ChannelOption.SO_KEEPALIVE, true)
    // .childOption(ChannelOption.TCP_NODELAY, true);
}
}

SipMessage
SipParser
等取自我的另一个开源项目pkts.io,但实际上与这个问题无关。只需知道,
SipMessage.toBuffer()
基本上只是吐出一个原始的
字节[]
,然后我将其传输到Netty传入的
ByteBuff

除非我执行
ctx.writeAndFlush(out)
,否则上述代码不起作用。然而,我认为,正如在Netty 3中一样,这个稍微高级的编码器的目的是保护我不受这些细节的影响。通过代码逐步调试
ByteBuf
被写入
ctx
但没有刷新,我想这就是它没有出现在套接字上的原因。因此,我的问题很简单:

  • 当我使用
    SipMessageEncoder
    时,为什么我必须自己调用
    ctx.writeAndFlush
    。Factorial示例中的
    numbercoder
    没有做到这一点,通过查看HTTP编解码器,我也看不到它做到了这一点,因此很明显,我遗漏了一些明显的东西
  • 另外,
    ByteBuf
    正在写入上下文,但从未刷新过,所以何时刷新?我试图通过一个TCP连接(使用sipp)推送大量流量,看看是否最终会强制刷新,但没有,没有任何结果
顺便说一句,我还尝试使用
MessageToMessageEncoder
,通过上下文分配ByteBuf并将其添加到
列表中,但结果相同

Btw2–我正在使用Netty 4.0.10.Final

谢谢

/Jonas

在向频道写入消息时,是否在其他地方调用flush()

“。您必须非常小心,以免在写入某些内容后忘记调用ctx.flush()。或者,您可以使用快捷方式writeAndFlush()。”

实际上,您不需要在SipMessageEncoder中调用write(),因为消息将由父MessageToByteEncode写入。如果以前没有调用过flush(),则只需调用flush()。

在向频道写入消息时,是否在其他地方调用flush()

“。您必须非常小心,以免在写入某些内容后忘记调用ctx.flush()。或者,您可以使用快捷方式writeAndFlush()。”


实际上,您不需要在SipMessageEncoder中调用write(),因为消息将由父MessageToByteEncode写入。如果以前没有调用过flush(),您只需要调用它。

嗨,Igor,不,我不调用flush,而且它实际上没有帮助,因为我自己没有写任何东西。也许我误解了MessageToByteEncoder的用法,但我的印象是,我将一个对象转换为另一个对象(在本例中为ByteBuf),在管道中的某个时候,它将被写入并刷新。我确信我只是错过了一些非常明显的东西。如果我在bytebuf上执行ctx.write和dflush,它会工作,但我并不真正理解消息ToByteEncoder的意义。嗨,伊戈尔,实际上我想我理解你的意思。不,我没有在我的SipMessageEncoder中调用flush,也许问题就在这里。我会试一试,如果成功的话,谢谢你让我走上正轨!非常感谢。我将在尝试后立即更新,但首先,实际工作:-)您知道,写入通道的所有消息都驻留在输出缓冲区中,直到调用flush()。主要使用场景如下:将消息写入通道,然后刷新()。每条消息都由MessageToByteEncoder序列化。这里不需要调用write()。在final flush()之后,所有消息都将写入该行。如果在SipMessageEncoder中调用flush()之前不调用它。是的,您完全正确。尽管我自己读了好几次,但我太专注于编码器了,以至于完全忽略了这个显而易见的东西。即使是阶乘的例子也能做到这一点,但出于某种原因,我没有将二和二相加。谢谢你的耐心,伊戈尔,非常感谢。嗨,伊戈尔,不,我不叫同花顺,实际上也没有帮助,因为我自己没有写任何东西。也许我误解了MessageToByteEncoder的用法,但我的印象是,我将一个对象转换为另一个对象(在本例中为ByteBuf),在管道中的某个时候,它将被写入并刷新。我确信我只是错过了一些非常明显的东西。如果我在bytebuf上执行ctx.write和dflush,它会工作,但我并不真正理解消息ToByteEncoder的意义。嗨,伊戈尔,实际上我想我理解你的意思。不,我没有在我的SipMessageEncoder中调用flush,也许问题就在这里。我会试一试,如果成功的话,谢谢你让我走上正轨!非常感谢。我将在尝试后立即更新,但首先,实际工作:-)您知道,写入通道的所有消息都驻留在输出缓冲区中,直到调用flush()。主要使用场景如下:将消息写入通道,然后刷新()。每条消息都由MessageToByteEncoder序列化。这里不需要调用write()。在final flush()之后,所有消息都将写入该行。如果在SipMessageEncoder中调用flush()之前不调用它。是的,您完全正确。尽管我自己读了好几次,我还是非常专注于编码器
public final class SipMessageEncoder extends MessageToByteEncoder<SipMessage> {

@Override
protected void encode(final ChannelHandlerContext ctx, final SipMessage msg, final ByteBuf out) throws Exception {
    final Buffer b = msg.toBuffer();
    for (int i = 0; i < b.getReadableBytes(); ++i) {
        out.writeByte(b.getByte(i));
    }
    out.writeByte(SipParser.CR);
    out.writeByte(SipParser.LF);
    // ctx.writeAndFlush(out);
}