writeAndFlush从不同的InboundChannelHandlerAdapter.channelRead

时间:2015-09-16 05:25:09

标签: sockets io netty

我遇到了一个问题,由于安全原因,我无法发布完整代码(抱歉)。我的问题的要点是我有一个ServerBootstrap,创建如下:

bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
final ServerBootstrap b = new ServerBootstrap();

b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)                        
.childHandler(new ChannelInitializer<SocketChannel>() {

@Override
public void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, 3000));
                                //Adds the MQTT encoder and decoder
                                ch.pipeline().addLast("decoder", new MyMessageDecoder());
                                ch.pipeline().addLast("encoder", new MyMessageEncoder());
                                ch.pipeline().addLast(createMyHandler());
                            }
                        }).option(ChannelOption.SO_BACKLOG, 128).option(ChannelOption.SO_REUSEADDR, true)
                        .option(ChannelOption.TCP_NODELAY, true)
                        .childOption(ChannelOption.SO_KEEPALIVE, true);

                // Bind and start to accept incoming connections.
                channelFuture = b.bind(listenAddress, listenPort);

使用createMyHandlerMethod()基本上返回ChannelInboundHandlerAdapter的扩展实现

我还有一个&#34;客户&#34;侦听器,侦听传入的连接请求,并按如下方式加载:

    final String host = getHost();
        final int port = getPort();
        nioEventLoopGroup = new NioEventLoopGroup();

        bootStrap = new Bootstrap();
        bootStrap.group(nioEventLoopGroup);
        bootStrap.channel(NioSocketChannel.class);
        bootStrap.option(ChannelOption.SO_KEEPALIVE, true);
        bootStrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, getKeepAliveInterval()));
                ch.pipeline().addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimeoutHandler());
                ch.pipeline().addLast("decoder", new MyMessageDecoder());
                ch.pipeline().addLast("encoder", new MyMessageEncoder());
                ch.pipeline().addLast(MyClientHandler.this);
            }
        })
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.TCP_NODELAY, true);

        // Start the client.
        try {
            channelFuture = bootStrap.connect(host, port).sync();
        } catch (InterruptedException e) {
            throw new MyException(“Exception”, e);
        }

MyClientHandler再次成为ChannelInboundHandlerAdapter的子类实例。一切正常,我收到来自&#34;服务器&#34;适配器,我处理它们,并在相同的上下文中发回它们。反之亦然#34;客户&#34;处理程序。

当我必须(对于某些消息)将它们从服务器或客户端处理程序代理到其他连接时,会发生问题。再一次,我很抱歉无法发布大量代码,但其中的主旨是我来自:

serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
     if (msg instanceof myProxyingMessage) {
        if (ctx.channel().isActive()) {
             ctx.channel().writeAndFlush(someOtherMessage);
             **getClientHandler().writeAndFlush(myProxyingMessage);**
        }
     }
}

现在问题在于:粗体(客户端)writeAndFlush - 从不实际写入消息字节,它不会抛出任何错误。 ChannelFuture返回所有false(成功,取消,完成)。如果我同步它,最终由于其他原因(我的代码中设置的连接超时)超时。

我知道我还没有发布我的所有代码,但我希望有人提供一些提示和/或指示,以解决为什么不写入客户端上下文的问题。我不是任何一个Netty专家,而且大部分代码都是由其他人编写的。它们都是ChannelInboundHandlerAdapter

的子类

如果您有任何问题,请随时提出任何问题。

***** EDIT ********* 我尝试使用以下测试代码将请求代理回不同的上下文/通道(即客户端通道):

public void proxyPubRec(int messageId) throws MQTTException {
        logger.log(logLevel, "proxying PUBREC to context:  " + debugContext());
        PubRecMessage pubRecMessage = new PubRecMessage();
        pubRecMessage.setMessageID(messageId);
        pubRecMessage.setRemainingLength(2);
        logger.log(logLevel, "pipeline writable flag:  " + ctx.pipeline().channel().isWritable());
        MyMQTTEncoder encoder = new MyMQTTEncoder();

        ByteBuf buff = null;
        try {
            buff = encoder.encode(pubRecMessage);
            ctx.channel().writeAndFlush(buff);

        } catch (Throwable t) {
            logger.log(Level.SEVERE, "unable to encode PUBREC");
        } finally {
            if (buff != null) {
                buff.release();
            }
        }
    }

    public class MyMQTTEncoder extends MQTTEncoder {
        public ByteBuf encode(AbstractMessage msg) {
            PooledByteBufAllocator allocator = new PooledByteBufAllocator();
            ByteBuf buf = allocator.buffer();
            try {
                super.encode(ctx, msg, buf);
            } catch (Throwable t) {
                logger.log(Level.SEVERE, "unable to encode PUBREC, " + t.getMessage());
            }
            return buf;
        }
    }

但是上面的第ctx.channel().writeAndFlush(buff)行不写入其他频道 - 调试此类问题的任何提示/技巧?

2 个答案:

答案 0 :(得分:0)

someOtherMessage必须为ByteBuf

所以,拿这个:

serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
     if (msg instanceof myProxyingMessage) {
        if (ctx.channel().isActive()) {
             ctx.channel().writeAndFlush(someOtherMessage);
             **getClientHandler().writeAndFlush(myProxyingMessage);**
        }
     }
}

...并将其替换为:

serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
     if (msg instanceof myProxyingMessage) {
        if (ctx.channel().isActive()) {
             ctx.channel().writeAndFlush(ByteBuf);
             **getClientHandler().writeAndFlush(myProxyingMessage);**
        }
     }
}

答案 1 :(得分:0)

实际上,这是一个线程问题。我的一个线程被阻塞/等待,而其他线程正在写入上下文,因此,即使使用刷新,写入也会被缓冲而不会被发送。问题解决了!

基本上,我将第一个消息代码放在Runnable / Executor线程中,这允许它单独运行,以便第二个写/响应能够写入上下文。这仍然存在一些问题(在消息排序方面),但这不是原始问题的主题。谢谢你的帮助!