在netty中汇集客户端渠道的正确方法?

时间:2013-04-03 23:07:21

标签: java netty

我在以下代码中收到java.nio.channels.NotYetConnectedException,因为我正在尝试写入尚未打开的频道。

基本上我所拥有的是一个频道池,我可以在其中获取一个频道,如果有空闲频道,我会创建一个新频道(如果没有频道)。我的问题是,当我创建一个新的通道时,当我调用connect时,通道还没有准备好写入,我不想在返回之前等待连接打开,因为我不想阻塞该线程。最好的方法是什么?另外,我检索/返回频道的逻辑是否有效?请参阅下面的代码。

我有一个简单的连接池,如下所示:

private static class ChannelPool {
    private final ClientBootstrap cb;
    private Set<Channel> activeChannels = new HashSet<Channel>();
    private Deque<Channel> freeChannels = new ArrayDeque<Channel>();
    public ChannelPool() {
        ChannelFactory clientFactory =
                new NioClientSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool());
        cb = new ClientBootstrap(clientFactory);
        cb.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() {
                return Channels.pipeline(
                        new HttpRequestEncoder(),
                        new HttpResponseDecoder(),
                        new ResponseHandler());
            }
        });
    }

    private Channel newChannel() {
        ChannelFuture cf;
        synchronized (cb) {
            cf = cb.connect(new InetSocketAddress("localhost", 18080));
        }
        final Channel ret = cf.getChannel();
        ret.getCloseFuture().addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture arg0) throws Exception {
                System.out.println("channel closed?");
                synchronized (activeChannels) {
                    activeChannels.remove(ret);
                }
            }
        });
        synchronized (activeChannels) {
            activeChannels.add(ret);
        }
        System.out.println("returning new channel");
        return ret;
    }

    public Channel getFreeChannel() {
        synchronized (freeChannels) {
            while (!freeChannels.isEmpty()) {
                Channel ch = freeChannels.pollFirst();
                if (ch.isOpen()) {
                    return ch;
                }
            }
        }
        return newChannel();
    }

    public void returnChannel(Channel ch) {
        synchronized (freeChannels) {
            freeChannels.addLast(ch);
        }
    }
}

我正在尝试在处理程序中使用它,如下所示:

private static class RequestHandler extends SimpleChannelHandler {

    @Override
    public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
        final HttpRequest request = (HttpRequest) e.getMessage();
        Channel proxyChannel = pool.getFreeChannel();
        proxyToClient.put(proxyChannel, e.getChannel());
        proxyChannel.write(request);
    }
}

1 个答案:

答案 0 :(得分:1)

不必在activeChannels之后立即将新频道添加到bootstrap.connect(..),而是必须为ChannelFuture返回的bootstrap.connect(..)添加一个侦听器,并添加频道添加到监听器中的activeChannels。这样,getFreeChannel()将永远不会获得尚未连接的频道。

因为即使您调用activeChannels newChannel(),即使在建立连接之前newChannel()也会返回',getFreeChannel()可能是空的,您必须决定在这种情况下该怎么做。如果我是你,我会将Channel的返回类型从ChannelFuture更改为{{1}},以便在免费频道准备就绪时通知来电。