2012-04-19 115 views
1

當您設計將連接到許多服務器的客戶端時,如爬行器。如何將應用程序/用戶數據傳遞給ChannelHandler Netty

編寫代碼,這樣的事情:當你在你的ApplicationHandler

// 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()); 
    } 
} 

現在,實現你的SimpleChannelHandler或WhatEverStreamHandler的東西,(在本例中CrawlerHander)的信息的唯一的一塊,你得到的是socketAdress你連接到你可以在「public void channelConnected()」函數中恢復。

好吧,但如果我想恢復一些用戶數據,如我在代碼示例中看到的MyURL對象,該怎麼辦?我使用一個骯髒的黑客,我使用一個地圖<「ip:port」,MyURL>所以我可以檢索channelConnected中的關聯數據,因爲我知道ip:port我連接上了。

這個黑客真的很髒,如果你同時連接到同一個服務器,它將無法工作(或者你必須綁定到本地端口並使用像「localport:ip:remoteport」這樣的密鑰,但它是太髒)。

所以我正在尋求什麼是傳遞數據的好方法CrawlerHander?

如果我們可以通過bootstrap的connect()方法傳遞這些數據,那將會很酷。我知道我可以在我的ChannelPipelineFactory.getPipeline()中傳遞參數,因爲它是通過connect()調用的。但是現在我們不能,所以這裏是另外一個骯髒的黑客我用:

編輯:

// 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()方法。但我無法找到關於它的郵件。 – 2012-04-19 19:30:01

+0

嘿,諾曼,你是在好的方式,我所有的問題將被解決,如果我可以傳遞附件在connect(),所以我可以通過我的ChannelPipelineFactory.getPipeline(Object theNewExtraParamater)傳遞給我的ChannelHandler()的consuctor; – Pierre 2012-04-20 05:39:24

+0

對不起,我的最後一句話不是同步問題,這是因爲我的另一種方法是弄髒,查看編輯過的帖子,我添加了一個代碼示例 – Pierre 2012-04-20 05:40:04

回答

0

您可以通過數據使用ChannelLocal或ChannelHandlerContext新連接信道/信道信息處理機(或使用連接未來的監聽器的最新的Netty 3.x中的Channel)。在下面的例子中,使用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(獲取數據)in Netty的最新3.x版本

但兩種方法都不支持rt類型安全。

+1

對不起,這不是一個很好的解決方案,在你的代碼示例,你不能肯定是由連接之前cf.addListener(新ChannelFutureListener()被調用,如果連接是立即連接後()該channedConnected功能將您的cf.addListener之前調用(新ChannelFutureListener(){」行 – Pierre 2012-04-20 05:19:57

+0

你錯了:),在實踐中這是不可能的,引導由NioWorker線程發射相應的事件之前一直執行未來的監聽器。例如。連接未來偵聽器將在處理程序的channelConnected之前執行() – 2012-04-20 05:55:41

+0

對不起老兄,你錯了,我不是在談論channelFutureListenner,我完全同意你的看法,將相關的事件之前被調用但是:問題你調用addListenner的方式,你可以在connect()之後調用addListenner如何確保連接在addLis之前不會被創建泰納?你不能。 – Pierre 2012-04-20 06:03:18

相關問題