【问题标题】:Why is ChannelHandlerContext.writeAndFlush() not processing my string?为什么 ChannelHandlerContext.writeAndFlush() 不处理我的字符串?
【发布时间】:2018-08-30 00:24:55
【问题描述】:

我正在使用 Netty 4.1.16 创建服务器。我建立了一个管道:

socketChannel.pipeline()
        //Line Based Frame Decoder will split a message into frames separated by CR/LF.
        // This one discards the delimiter and fails on excessive length only when the
        // entire frame has been read.
        .addLast("Frame Decoder", new LineBasedFrameDecoder(MAX_FRAME_LENGTH, true, false))
        // String decoder changes inbound byte stream into a string.
        .addLast("String Decoder", new StringDecoder(CharsetUtil.US_ASCII))
        // VoiceMessage is a custom decoder that turns a string into a socket message
        // and passes it to a command handler thread.
        .addLast("VoiceMessage Decoder", new InboundVoiceHandler())
        // String encoder allows us to write a string directly to the channel without needing
        // to write a custom string-to-byte encoder.
        .addLast("String Encoder", new StringEncoder(CharsetUtil.US_ASCII));

稍后在我的代码中,我创建了一个对传入消息的字符串响应,并尝试使用以下方法将其写入 ChannelHandlerContext:

    message = pack.getBoardList() == null || pack.getBoardList().size() > 0
            ? "Existing pack number " + pack.getPackNo() + " has been recalled."
            : "New pack number " + pack.getPackNo() + " has been started.";
    new OutboundTalkmanMessage(channelHandlerContext, voiceMessage.getVoiceSession())
            .writeAndFlush(message, vdtsSysDB);

...

public class OutboundTalkmanMessage {
    private VoiceSession voiceSession;
    private ChannelHandlerContext ctx;

    private static final Logger LOG = LoggerFactory.getLogger(OutboundTalkmanMessage.class);

    public OutboundTalkmanMessage(ChannelHandlerContext ctx, VoiceSession voiceSession) {
        this.ctx = ctx;
        this.voiceSession = voiceSession;
    }

    public void writeAndFlush(String message, VdtsSysDB vdtsSysDB) {
        saveOutgoingMessage(message, vdtsSysDB);
        String talkmanMessage = "\"" + message + "\"\r\n\n";
        LOG.info("Ougoing message: [{}]", talkmanMessage);
        try {
            ChannelFuture channelFuture = ctx.writeAndFlush(talkmanMessage);
            LOG.info("Waiting for write.");
            channelFuture.addListener(future -> {
                if (future.isSuccess()) LOG.info("Write succeeded.");
                else {
                    LOG.error("Write failed. {}", future.cause());
                }
                LOG.info("Message sent.");
                ctx.close();
            });
        } catch (Exception e) {
            LOG.error("Error writing talkman output.", e);
        }
    }
}

我的 ChannelHandlerContext.writeAndFlush(String msg) 失败,原因是

java.lang.UnsupportedOperationException: unsupported message type: String (expected: ByteBuf, FileRegion)

据我了解文档和示例,writeAndFlush 应将字符串写入管道,字符串编码器应将该字符串更改为 bytebuf,然后再将其转发到套接字进行传输。 我检查了通道管道,StringEncoder 肯定是在那里注册的。我已经尝试通过 Netty 库遵循执行路径,但这种方式很疯狂。 我使用了错误的写调用吗? writeAndFlush 是否跳过了 StringEncoder?我应该放弃编程并回到我作为碰撞测试假人的工作吗?

【问题讨论】:

  • 您是否在InboundVoiceHandler 内致电writeAndFlush()?如果是这样,您可能会绕过StringEncoder。您是否尝试过在管道中交换 StringEncoderInboundVoiceHandler 的顺序?

标签: java netty


【解决方案1】:

我认为你想使用Channel.writeAndFlush 来确保你走完整个ChannelPipeline。您很可能使用ChannelHandler 中的ChannelHandlerContext,它位于StringEncoder 之前,因此不会被它处理。

【讨论】:

  • 从我的阅读中,我的印象是 ChannelHandlerContext.writeAndFlush 总是从管道的末端遍历到它的开头......事实并非如此,正如上面的注释所指出的那样。将 StringEncoder 移到堆栈更高的位置解决了这个问题,尽管使用 Channel.writeAndFlush 可能是更正确的方法。
猜你喜欢
  • 2018-01-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-07
相关资源
最近更新 更多