2012-03-16 17 views
8

Sono nuovo di Netty e ancora strugling di trovare la mia strada. Sto cercando di creare un client http che funzioni in modo asincrono. Gli esempi Netty di http mostrano solo come aspettare per le operazioni di IO, e non come utilizzare addListener, e così ho cercato di conoscere questo numero per gli ultimi giorni.client asincroni HTTP con Netty

Sto cercando di creare una classe richiesta che gestirà tutti i diversi stati di una richiesta, di connettersi, l'invio dei dati, la gestione della risposta e quindi la chiusura della connessione. Per fare ciò la mia classe si estende SimpleChannelUpstreamHandler e implementa ChannelFutureListener. Io uso uno ChannelPipelineFactory che aggiunge l'istanza (this) alla classe (come SimpleChannelUpstreamHandler) alla pipeline come gestore.

La connessione viene creata in questo modo:

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

Poi il metodo dioperationComplete:

@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; 
} 

La classe ignora anche la messageReceived metodo:

@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)); 
    } 
} 

Il problema è che ottengo questo output:

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 

Come si può vedere la messageReceived del non viene eseguito per qualche ragione, anche se la fabbrica gasdotto aggiunge l'istanza di questa classe per la pipeline.

Tutte le idee che mi manca qui? Grazie.


Modifica

sono riuscito ad ottenere finalmente questo grazie lavorano all'aiuto di @JestanNirojan, nel caso in cui qualcuno sarà interessato a una soluzione:

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 la HttpResponse pieno o può essere un pezzo di TI?Ho 1000 di pezzi che tornano e voglio un evento per chunk o la memoria esploderà con conseguente esaurimento della memoria. –

+0

HttpResponse è la risposta completa, non puoi ridurlo per quanto ne so. Dovresti andare più in basso, probabilmente con [HttpResponseDecoder] (http://static.netty.io/3.5/api/org/jboss/netty/handler/codec/http/HttpResponseDecoder.html). –

+0

Se non sei interessato a chunking usa il client http chiaro qui @ https://github.com/arungeorge81/netty-http-client –

risposta

3

Si utilizza un ChannelFutureListener a fai tutte le operazioni nel canale (che è male), e il futuro ascoltatore verrà eseguito subito dopo aver chiamato quelle operazioni di canale.

Il problema è, dopo l'invio del messaggio, il canale viene scollegata immediatamente e il gestore non può ricevere il messaggio di risposta che viene dopo.

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

non si dovrebbe bloccare affatto il thread del canale futuro. L'approccio migliore è estendere

channelConnected(..) {} 
    messageReceived(..) {} 
    channelDisconnected(..) {} 

metodi del SimpleChannelUpstreamHandler e reagire a quegli eventi. puoi mantenere lo stato anche in quel gestore.

+1

Oh. E 'stato semplice Grazie mille per le informazioni, vorrei che Netty avesse una documentazione migliore su questo. –