netty:为什么处理程序中的代码不能使用future.await()?

时间:2012-03-19 02:09:45

标签: netty

每个人,你好!

我使用netty 3.1来构建一个套接字调度服务器,它将套接字数据传输到另一个套接字服务器,所以当第一条消息到达时,我在netty服务器处理程序中创建一个客户端连接,等待单元连接完成,当下一个messageRecv事件到达时,我只是将缓冲区从服务器通道传输到客户端通道。但是我发现在使用future.await *()操作时禁止处理程序。如果我不使用await(),因为connectFuture是同步的,有可能在下一条消息到达时,但是conenct未完成。我不知道如何处理这个问题。

如何在下一个messageRecv事件到达之前确保客户端连接完成?

现在,我只是锁定同步两个代码,就像这样:

/**
 * server handler
*/
public class ServerChannelHandler extends SimpleChannelUpstreamHandler {

  private static Logger _logger = LoggerFactory.getLogger(cn.szboc.dispatch.server.netty.ServerChannelHandler.class);

  public ServerChannelHandler(ProxyClientFactory clientFactory) {
    this.clientFactory = clientFactory;
  }

/** factory connect another server */
private ProxyClientFactory clientFactory;

/** anotherchannel */
private Channel innerChannel;

private ChannelFuture connectFuture;


private ReentrantLock connectLock = new ReentrantLock();

private Condition notComplete = connectLock.newCondition();

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

    final ChannelBuffer buffer = ((ChannelBuffer) e.getMessage()).copy();
    final Channel outChannel = ctx.getChannel();

    // first connect
    if (connectFuture == null) {

        final ClientChannelHandler cch = new ClientChannelHandler(ctx.getChannel());

        ProxyClient client = clientFactory.retrieveClient();


        connectFuture = client.getConnectChannelFuture();


        connectFuture.addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture future) throws Exception {

                connectLock.lock();
                try {

                    if (future.isSuccess()) {
                        innerChannel = future.getChannel();

                        innerChannel.getPipeline().addLast("clientchannelhandler", cch);
                        innerChannel.write(buffer);
                    } else {

                        Channels.fireExceptionCaught(outChannel, future.getCause());
                    }
                } finally {

                    notComplete.signal();

                    connectLock.unlock();
                }
            }

        });

    } else {

        connectLock.lock();
        try {

            if (!connectFuture.isDone()) {

                if (!notComplete.await(500, TimeUnit.MILLISECONDS)) {

                    throw new Exception("");
                }
            }


            if (connectFuture.isSuccess()) {
                if(innerChannel == null){
                    if (!notComplete.await(500, TimeUnit.MILLISECONDS)) {

                        throw new Exception("");
                    }
                }
                innerChannel.write(buffer);
            } else {

                _logger.error("");
            }

        } finally {
            connectLock.unlock();
        }

    }

}

1 个答案:

答案 0 :(得分:1)

你不能,因为你可以使网络陷入僵局。你也会阻止IO-Worker线程,这是一件坏事。处理您的情况的最佳方法是“排队”消息,直到连接完成,然后分发它们。

另一种解决方案是在“channelOpen(..)”方法上连接到代理客户端,同时设置Channel.setReadable(false)。连接完成后,您将再次调用Channel.setReadable(true),以便处理messageEvents。

这样的事情:

    @Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
        throws Exception {
    // Suspend incoming traffic until connected to the remote host.
    final Channel inboundChannel = e.getChannel();
    inboundChannel.setReadable(false);

    // Start the connection attempt.
    ClientBootstrap cb = new ClientBootstrap(cf);
    cb.getPipeline().addLast("handler", new OutboundHandler(e.getChannel()));
    ChannelFuture f = cb.connect(new InetSocketAddress(remoteHost, remotePort));

    outboundChannel = f.getChannel();
    f.addListener(new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            if (future.isSuccess()) {
                // Connection attempt succeeded:
                // Begin to accept incoming traffic.
                inboundChannel.setReadable(true);
            } else {
                // Close the connection if the connection attempt has failed.
                inboundChannel.close();
            }
        }
    });
}

有关更多详细信息,请参阅代理示例[1]。

[1]  https://github.com/netty/netty/tree/3.2/src/main/java/org/jboss/netty/example/proxy