2012-03-16 13 views
8

私はnettyを初めて使っています。私は、非同期に動作するhttpクライアントを作成しようとしています。 httpのnettyの例は、どのようにIO操作を待つかを示していますが、addListenerの使い方を示していないので、ここ数日間はこれを把握しようとしています。Nettyを使用した非同期HTTPクライアント

リクエストのさまざまな状態をすべて処理し、接続、データの送信、応答の処理、接続の終了を行うリクエストクラスを作成しようとしています。 私のクラスは、SimpleChannelUpstreamHandlerを拡張し、ChannelFutureListenerを実装しています。私はChannelPipelineFactoryを使用して、(this)インスタンスをクラス(SimpleChannelUpstreamHandlerとして)をパイプラインにハンドラとして追加します。

接続は次のように作成される:

this.state = State.Connecting; 
this.clientBootstrap.connect(this.address).addListener(this); 

そしてoperationComplete方法:

@Override 
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { 
    System.out.println("messageReceived"); 
    HttpResponse response = (HttpResponse) e.getMessage(); 

    ChannelBuffer content = response.getContent(); 
    if (content.readable()) { 
     System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8)); 
    } 
} 

@Override 
public void operationComplete(ChannelFuture future) throws Exception { 
    State oldState = this.state; 

    if (!future.isSuccess()) { 
     this.status = Status.Failed; 
     future.getChannel().disconnect().addListener(this); 
    } 
    else if (future.isCancelled()) { 
     this.status = Status.Canceled; 
     future.getChannel().disconnect().addListener(this); 
    } 
    else switch (this.state) { 
     case Connecting: 
      this.state = State.Sending; 
      Channel channel = future.getChannel(); 
      channel.write(this.createRequest()).addListener(this); 
      break; 

     case Sending: 
      this.state = State.Disconnecting; 
      future.getChannel().disconnect().addListener(this); 
      break; 

     case Disconnecting: 
      this.state = State.Closing; 
      future.getChannel().close().addListener(this); 
      break; 

     case Closing: 
      this.state = State.Finished; 
      break; 
    } 
    System.out.println("request operationComplete start state: " + oldState + ", end state: " + this.state + ", status: " + this.status); 
} 

private HttpRequest createRequest() { 
    String url = this.url.toString(); 

    HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url); 
    request.setHeader(HttpHeaders.Names.HOST, this.url.getHost()); 
    request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); 
    request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); 

    return request; 
} 

クラスは、messageReceivedメソッドをオーバーライドあなたはは、パイプラインの工場は、パイプラインに、このクラスのインスタンスを追加していても、何らかの理由で実行されていないのをmessageReceived見ることができるように

request operationComplete start state: Connecting, end state: Sending, status: Unknown 
request operationComplete start state: Sending, end state: Disconnecting, status: Unknown 
request operationComplete start state: Closing, end state: Finished, status: Unknown 
request operationComplete start state: Disconnecting, end state: Finished, status: Unknown 

:問題は、私はこの出力を得ることです。

私はここで何が欠けているのですか?おかげさまで


私はようやく場合には、誰かが溶液中で興味があるだろう、@JestanNirojanのヘルプにこの作業感謝を得ることができた

編集:

public class ClientRequest extends SimpleChannelUpstreamHandler { 

    .... 

    public void connect() { 
     this.state = State.Connecting; 
     System.out.println(this.state); 
     this.clientBootstrap.connect(this.address); 
    } 

    @Override 
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     this.state = State.Sending; 
     System.out.println(this.state); 
     ctx.getChannel().write(this.createRequest()); 
    } 

    @Override 
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { 
     HttpResponse response = (HttpResponse) e.getMessage(); 

     ChannelBuffer content = response.getContent(); 
     if (content.readable()) { 
      System.out.println("CONTENT: " + content.toString(CharsetUtil.UTF_8)); 
     } 

     this.state = State.Disconnecting; 
     System.out.println(this.state); 
    } 

    @Override 
    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     this.state = State.Closing; 
     System.out.println(this.state); 
    } 

    @Override 
    public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { 
     this.state = State.Finished; 
     System.out.println(this.state); 
    } 

    private HttpRequest createRequest() { 
     String url = this.url.toString(); 

     HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url); 
     request.setHeader(HttpHeaders.Names.HOST, this.url.getHost()); 
     request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); 
     request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); 

     return request; 
    } 
} 
+0

はHttpResponseであり、完全なHttpResponseであるか、またはチャンクである可能性がありますか?私は1000のチャンクが戻ってきてチャンクごとに1つのイベントが必要な場合、またはメモリが爆発してメモリが不足します。 –

+0

HttpResponseは完全な応答です。私が知る限り、それをチャンクすることはできません。おそらく、[HttpResponseDecoder](http://static.netty.io/3.5/api/org/jboss/netty/handler/codec/http/HttpResponseDecoder.html)を使って、それより低くする必要があります。 –

+0

あなたがチャンクに入れられていない場合は、ここで軽いhttpクライアント@ https://github.com/arungeorge81/netty-http-client –

答えて

3

あなたがにChannelFutureListenerを使用していますチャンネルのすべての操作を行う(悪い)、将来のリスナーは、そのチャンネル操作を呼び出した直後に実行されます。

問題は、メッセージを送信した後すぐにチャネルが切断され、ハンドラは後で返される応答メッセージを受信できません。

 ........ 
    case Sending: 
     this.state = State.Disconnecting; 
     future.getChannel().disconnect().addListener(this); 
     break; 
     ........ 

チャネルの将来のスレッドをブロックしないでください。最善の方法は、SimpleChannelUpstreamHandlerのメソッドを拡張して、それらのイベントに反応することです。そのハンドラにも状態を保持することができます。

+1

Ohを使用してください。それは簡単だった。情報をありがとう、私はNettyがこれに関するより良い文書を持っていたらいいと思う。 –

関連する問題