2012-04-19 9 views
1

クローラのような多くのサーバーに接続するクライアントを設計するとき。アプリケーション/ユーザーデータをChannelHandler Nettyに渡す方法

あなたはそのようなコードになります:あなたはApplicationHandler、あなたのSimpleChannelHandlerやWhatEverStreamHandlerを実装もの、(例でCrawlerHander)にあるとき今、あなたが得る唯一の情報がある

// the pipeline 
public class CrawlerPipelineFactory implements ChannelPipelineFactory { 
    public ChannelPipeline getPipeline() throws Exception { 
     return Channels.pipeline(new CrawlerHandler()); 
    } 
} 

// the channel handler 
public class CrawlerHandler extends SimpleChannelHandler { 
    @Override 
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     // ... 
    } 
} 


// the main : 
public static void main(){ 
    ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool()); 

    ClientBootstrap scannerBootstrap = new ClientBootstrap(factory); 
    scannerBootstrap.setPipelineFactory(new CrawlerPipelineFactory()); 

    while(true){ 
     MyURL url = stack.pop(); 
     ChannelFuture connect = scannerBootstrap.connect(url.getSocketAddress()); 
    } 
} 

をsocketAdressあなたは "public void channelConnected()"関数でリカバリできることに接続しています。

しかし、コード例に表示されるMyURLオブジェクトのようなユーザーデータを回復したい場合はどうすればよいですか?

私は地図< "ip:port"、MyURL>を使用しているので、ip:port iが接続されていることを知っているので、channelConnectedの関連データを取得できます。

このハックは本当に汚いです。同じサーバーに同時に接続している場合(またはローカルポートにバインドして「localport:ip:remoteport」のようなキーを使用する必要がありますが、とても汚い)。

私は、データをCrawlerHanderに渡すための良い方法は何ですか?

このデータをブートストラップのconnect()メソッドで渡すことができれば、クールです。 ChannelPipelineFactory.getPipeline()は、connect()を介して呼び出されるため、引数を渡すことができます。しかし、今、私たちはそうここに私が使用して別の汚いハックです、することはできません。

EDIT:

// the main 
while(!targets.isEmpty()){ 
    client.connect("localhost",111); // we will never connect to localhost, it's a hack 
} 

// the pipleline 
public ChannelPipeline getPipeline() throws Exception { 
    return Channels.pipeline(
     new CrawlerHandler(targets.pop()) // I specify each new host to connect here 
    ); 
} 

// in my channel handler 
// Now I have the data I want in the constructor, so I m sure I get them before everything is called 
public class CrawlerHandler extends SimpleChannelHandler { 
    ExtraParameter target; 
    public CrawlerHandler(ExtraParameter target) { 
     this.target = target; 

// but, and it's the most dirty part, I have to abort the connection to localhost, and reinit a new connection to the real target 
    boolean bFirstConnect=true; 
    @Override 
    public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     if(bFirstConnect){ 
      bFirstConnect = false; 
      ctx.getChannel().connect(target.getSocketAddr()); 
     } 
+0

あなたが話している同期の問題は何ですか?それをChannelPipelineFactoryに渡すと、atmに行くことができます。私はconnectメソッドで何らかのアタッチメントを渡すことができるようになる前に、ChannelPipeline.getPipeline()メソッドに自動的に渡されるというアイデアがあったと思います。しかし、私はそれについての電子メールをatm見つけることができませんでした。 –

+0

ちょっとノーマン、あなたは良い方法であり、私がChannelPipelineFactory.getPipeline(Object theNewExtraParamater)経由で私のChannelHandler()のコンスータに渡すことができるように、connect()で添付ファイルを渡すことができれば、私の問題はすべて解決されます。 – Pierre

+0

最後の文章は残念ですが同期問題ではありませんでした。私のもう1つの方法は汚れていて、編集した記事を見ています。コード例 – Pierre

答えて

0

は、あなたはChannelLocalを使用して、新たに接続されたチャネル/チャネルハンドラまたはChannelHandlerContextに(またはにデータを渡すことができます将来のリスナーを使用して、最新のNetty 3.xのチャンネルそれ自身)以下の例では、ChannelLocalが使用されています。

public class ChannelDataHolder { 
    public final static ChannelLocal<String> CHANNEL_URL = new ChannelLocal<String>(true); 
} 

    // for each url in bootstrap 

    MyURL url = ....; 
    ChannelFuture cf = scannerBootstrap.connect(url.getSocketAddress()); 

    final String urlString = url.getUrl(); 

    cf.addListener(new ChannelFutureListener() { 
      @Override 
      public void operationComplete(ChannelFuture future) throws Exception { 
       ChannelDataHolder.CHANNEL_URL.set(future.getChannel(), urlString); 
      } 
    }); 



    //In the handler 

public class CrawlerHandler extends SimpleChannelHandler { 
    @Override 
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     String urlString = ChannelDataHolder.CHANNEL_URL.get(ctx.getChannel()); 
     // ...use the data here 
    } 
} 

注:代わりにChannelLocalの、あなたが設定し

  • ChannelHandlerContext.setAttachment()/ getAttachment()

  • Channel.setAttachment()/ getAttachment(使用してデータを取得することができます)最新の3.xバージョンのNetty

でもどちらの方法もサポートしていませんrtタイプの安全性。

+1

申し訳ありませんが、これは良い解決策ではありません。コード例では、接続が行われる前にcf.addListener(new ChannelFutureListener()が呼び出されることはありません。実際には不可能なcf.addListener(new ChannelFutureListener(){"line – Pierre

+0

あなたが間違っています:)の前に、channedConnected関数が呼び出されます。NioWorkerスレッドによってそれぞれのイベントが発生する前に、チャネルの将来のリスナーが常に実行されます。将来のリスナーをハンドラのchannelConnected()の前に実行します。 –

+0

申し訳ありませんが、間違っています。私はchannelFutureListennerについて話しているわけではありませんが、関連イベントの前に呼び出されることに全く同意します。 addListennerを呼び出す方法、connect()の後にaddListennerを呼び出すaddLisの前に接続が確立されていないことを確認する方法テナー?できません。 – Pierre

関連する問題