クローラーなど、多数のサーバーに接続するクライアントを設計する場合。
あなたはそのようなものをコーディングします:
// 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());
}
}
これで、ApplicationHandlerにいるときに、SimpleChannelHandlerまたはWhatEverStreamHandler(例ではCrawlerHander)を実装するものだけが、「public voidchannelConnected()」関数で回復できる接続先のsocketAdressです。 。
わかりましたが、コード例にあるMyURLオブジェクトなど、一部のユーザーデータを復元したい場合はどうすればよいですか?
ダーティハックを使用しています。Map<"ip:port"、MyURL>を使用しているので、接続しているip:portがわかっているので、channelConnectedで関連データを取得できます。
このハックは本当に汚いです。同じサーバーに同時に接続している場合は機能しません(または、ローカルポートにバインドして、「localport:ip:remoteport」などのキーを使用する必要がありますが、とても汚いです)。
だから私はCrawlerHanderにデータを渡すための良い方法は何ですか?
ブートストラップのconnect()メソッドを介してこのデータを渡すことができれば素晴らしいでしょう。引数はconnect()を介して呼び出されるため、ChannelPipelineFactory.getPipeline()で引数を渡すことができます。しかし、今はできないので、ここに私が使用する別の汚いハックがあります:
編集:
// 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());
}