2011-11-20 8 views
6

Próbowałem następujący przykład Apache klienta http:HTTPClient 4.x Connection używać ponownie dzieje

http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientMultiThreadedExecution.java

ustawić maksymalną wielkość puli jako 5 i uruchomić dziesięć wątków. Po uruchomieniu tego kodu, gdy sprawdzam netstat, widzę 10 otwartych połączeń TCP. Spodziewałem się, że połączenia zostaną ponownie wykorzystane. Dlaczego to ? Czy czegoś brakuje?

Fragment kodu jest jak poniżej:

public class ClientMultiThreadedExecution { 
public static void main(String[] args) throws Exception { 

    SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    schemeRegistry.register(
    new Scheme("http", 18080, PlainSocketFactory.getSocketFactory())); 

    ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(schemeRegistry); 
    cm.setDefaultMaxPerRoute(5); 
    cm.setMaxTotal(5); 


    HttpClient httpclient = new DefaultHttpClient(cm); 
    try { 
     // create an array of URIs to perform GETs on 
     String uri = "http://test.webservice.com:18080/TestServlet"; 
     String data = "This is a test message"; 

     System.out.println("Started at: " + new Date()); 
     // creating 10 threads 
     PostThread[] threads = new PostThread[10]; 

     for (int i = 0; i < threads.length; i++) { 
     HttpPost httpPost = new HttpPost(uri); 
     threads[i] = new PostThread(httpclient, httpPost, data, i + 1); 
      threads[i].start(); 
      //Thread.sleep(1000); 
     } 

     // join the threads 
     for (int j = 0; j < threads.length; j++) { 
      threads[j].join(); 
     } 

    } finally { 
     // When HttpClient instance is no longer needed, 
     // shut down the connection manager to ensure 
     // immediate deallocation of all system resources 
     System.out.println("Ended at: " + new Date()); 
     httpclient.getConnectionManager().shutdown(); 
    } 
} 

/** 
* A thread that performs a POST. 
*/ 
static class PostThread extends Thread { 

    private final HttpClient httpClient; 
    private final HttpContext context; 
    private final HttpPost httpPost; 
    private final int id; 
    private final String data; 

    public PostThread(HttpClient httpClient, HttpPost httpPost, String data, int id) { 
     this.httpClient = httpClient; 
     this.context = new BasicHttpContext(); 
     this.httpPost = httpPost; 
     this.id = id; 
     this.data = data; 
    } 

    /** 
    * Executes the PostMethod and prints some status information. 
    */ 
    @Override 
    public void run() { 

     //System.out.println(id + " - about to get something from " + httpPost.getURI()); 

     try { 

      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1); 
      nameValuePairs.add(new BasicNameValuePair("XML",data)); 
      httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs,"UTF-8")); 

      // execute the method 
      HttpResponse response = httpClient.execute(httpPost, context); 

      //System.out.println(id + " - get executed"); 
      // get the response body as an array of bytes 
      if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) 
       System.out.println("Success"); 

      //Is this step necessary ?? Need to check as only status code is required 
      //httpPost.abort(); 
      //HttpEntity entity = response.getEntity(); 

      //And this ? 
      //EntityUtils.consume(entity); 

     } catch (Exception e) { 
      httpPost.abort(); 
      System.out.println(id + " - error: " + e); 
     } 
    } 

}} 
+1

Rozwiązaniem było specjalnie wspomnieć wersję protokołu jako HTTP_1_1: 'HttpProtocolParams.setVersion (params, HttpVersion.HTTP_1_1);'. Łączenie następnie działało. – Dunxton

+0

Czego potrzebujemy do utrzymania w miejscu params oznacza jaką wartość i gdzie musimy umieścić to stwierdzenie w kodzie – Labeo

Odpowiedz

11

 //Is this step necessary ?? Need to check as only status code is required 
     //httpPost.abort(); 
     //HttpEntity entity = response.getEntity(); 

     //And this ? 
     //EntityUtils.consume(entity); 

wiecie co? To jest.

Jeden MUSI zapewnić, że zawartość odpowiedzi zostanie zużyta, aby połączenie podstawowe zostało zwolnione z powrotem do menedżera połączeń. Inwokacja albo EntityUtils#consume lub httpUriRequest#abort wyzwala zwolnienie połączenia z powrotem do puli. Różnica polega na tym, że pierwsza próbuje utrzymać połączenie przy życiu, podczas gdy druga nie.

+0

Co powiecie na ten blok kodu? 'catch (wyjątek e) { httpPost.abort(); System.out.println (id + "- error:" + e); } 'Ilekroć wystąpi wyjątek, zostaje wywołana metoda httpPost.abort(). Jednak zauważam, że to samo przerwane połączenie jest nadal przekazywane innym wątkom, a wszystkie z nich powodują błąd z komunikatem "java.io.IOException: Request already aborted". Dlaczego to się dzieje ? – Dunxton

+2

@Dunxton Przerwane połączenia są natychmiast odrzucane i eksmitowane z puli. Próbujesz ponownie użyć przerwanej prośby. Nie rób tego. Żądaj obiektów są tanie. – oleg

Powiązane problemy