1. 程式人生 > >httpclient請求報 java.net.BindException: Address already in use

httpclient請求報 java.net.BindException: Address already in use

參考文件:

http://liuinsect.iteye.com/blog/1886237

http://www.iteye.com/topic/234759

http://blog.csdn.net/kobejayandy/article/details/16921265

為了更好的提供文章,我已經將部落格遷移到了自建的部落格網站上,我將更多的從原始碼分析的角度入手,為大家帶來更多的深度文章,請大家繼續關注我~!  部落格地址:www.liuinsect.com

_______________________________________________________________________________

MultiThreadedHttpConnectionManager 是HTTP Client中用來複用連線的連線管理類,可以通過

Java程式碼  收藏程式碼

  1. MultiThreadedHttpConnectionManager n =  new MultiThreadedHttpConnectionManager();  
  2. HttpClient client = new HttpClient(n);  

這樣的方式去 建立一個Client 例項,

建立後,每當執行

int statusCode = client.executeMethod(postMethod);時 

http client 委託ConnectionManager建立連線,其實是先委託HttpMethodDirector 執行excute方法,

再通過它委託ConnectionManager 建立連線,HttpMethodDirector 中包含了一下host,請求引數等資訊。

在建立連線時,HttpMethodDirector 中有如下程式碼:

Java程式碼  收藏程式碼

  1. if ( this.conn == null) {  
  2.     this.conn = connectionManager.getConnectionWithTimeout(  
  3.         hostConfiguration,  
  4.         this.params.getConnectionManagerTimeout()  
  5.      );  
  6.     ......  
  7.  }  

ConnectionManager 使用了常用的多型的方式將連線的獲取交給子類完成。 增強其擴充套件性。

ConnectionManager 有三個子類:

 
 

對應於:

1. 一次性的連線:


 

 2. 執行緒池中獲取連線:

 

 

3. 複用當前SimpleHttpConnectionManager中的一個成員變數,策略是沒有則建立,有則覆蓋後返回

 

 

重點說下MultiThreadedHttpConnectionManager   中連線的獲取

在使用 MultiThreadedHttpConnectionManager  獲取連線的時候,MultiThreadedHttpConnectionManager  使用了連線池的概念針對每個
HostConfiguration 做了連線的管理,即 HostConfiguration 作為Key ,連線池(HostConnectionPool)作為value去管理當前host下的所有連線,
HostConfiguration的例項如下: HostConfiguration[host=http://www.taobao.com]

HostConnectionPool 中使用連結串列 管理了 空閒的連線和等待連線的執行緒佇列。

每次獲取連線的時候 根據引數(後面會提到)決定是直接從池中獲取一個空閒連線,建立一個連線,還是計算出一個等待時間後 將當前執行緒沉睡這麼久。而後再檢查。


Http Client 通過協議對應的ProtocolSocketFactory去建立一個socket連線來發送請求和接受響應

使用注意事項:

1. MultiThreadedHttpConnectionManager  中有以下兩個變數,分別解釋:

     a. 每個host最大同時可以獲取的連線數, 大於這個數字後, (1,2號執行緒正在使用連線)3號執行緒會wait 沉睡住 直到到達時間或者被打斷或者1,2號中有人release這個connection,丟擲異常。

          注意,如果是HTTP client 來呼叫介面的話 這個例如(http://www.taobao.com 那他的host是www.taobao.com) 這個值應該設定大一點 否則很多執行緒呼叫這個介面的時候會阻塞住。

     b. 同一時間MultiThreadedHttpConnectionManager  允許的最大連線數,超過這個數字,連線的建立將會阻塞。直到有空閒連線釋放。

 

 

使用注意事項測試程式碼:  下劃線的兩個方法可以調整後觀察結果

Java程式碼  收藏程式碼

  1. public static void main(String[] sadfasd) throws HttpException, IOException, InterruptedException{  
  2.              final String url= "http://www.taobao.com" ;  
  3.              final HttpClient client = new HttpClient();  
  4.              final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();  
  5.              connectionManager.setMaxTotalConnections (1);//總的連線數  
  6.              connectionManager.setMaxConnectionsPerHost (2);//每個host的最大連線數  
  7.             client.setHttpConnectionManager( connectionManager );  
  8.             Runnable r = new Runnable(){  
  9.                    public  void run(){  
  10.                          int statusCode=0;  
  11.                         PostMethod postMethod = new PostMethod(url);  
  12.                          try {  
  13.                               statusCode = client.executeMethod(postMethod);  
  14.                               System. out.println( "sleep" + statusCode );  
  15.                               Thread. sleep(3000);//10s  
  16.                               postMethod.releaseConnection();  
  17.                         } catch (HttpException e) {  
  18.                               e.printStackTrace();  
  19.                         } catch (IOException e) {  
  20.                               e.printStackTrace();  
  21.                         } catch (InterruptedException e) {  
  22.                               e.printStackTrace();  
  23.                         }  
  24.                   };  
  25.             };  
  26.             Runnable r1 = new Runnable(){  
  27.                    public  void run(){  
  28.                          int statusCode=0;  
  29.                         PostMethod postMethod = new PostMethod(url);  
  30.                          try {  
  31.                               statusCode = client.executeMethod(postMethod);  
  32.                         } catch (HttpException e) {  
  33.                               e.printStackTrace();  
  34.                         } catch (IOException e) {  
  35.                               e.printStackTrace();  
  36.                         }  
  37.                         System. out.println( statusCode );  
  38.                         postMethod.releaseConnection();  
  39.                   };  
  40.             };  
  41.             Runnable r2 = new Runnable(){  
  42.                    public  void run(){  
  43.                          int statusCode=0;  
  44.                         PostMethod postMethod = new PostMethod(url);  
  45.                          try {  
  46.                               statusCode = client.executeMethod(postMethod);  
  47.                         } catch (HttpException e) {  
  48.                               e.printStackTrace();  
  49.                         } catch (IOException e) {  
  50.                               e.printStackTrace();  
  51.                         }  
  52.                         System. out.println( statusCode );  
  53.                         postMethod.releaseConnection();  
  54.                   };  
  55.             };  
  56.             Runnable r3 = new Runnable(){  
  57.                    public  void run(){  
  58.                          int statusCode=0;  
  59.                         PostMethod postMethod = new PostMethod(url);  
  60.                          try {  
  61.                               statusCode = client.executeMethod(postMethod);  
  62.                         } catch (HttpException e) {  
  63.                               e.printStackTrace();  
  64.                         } catch (IOException e) {  
  65.                               e.printStackTrace();  
  66.                         }  
  67.                         System. out.println( statusCode );  
  68.                         postMethod.releaseConnection();  
  69.                   };  
  70.             };  
  71.              new Thread(r).start();  
  72.             Thread. sleep(1000);  
  73.              new Thread(r1).start();  
  74.              new Thread(r2).start();  
  75.              new Thread(r3).start();  
  76.       }  

釋放連線:

在我們呼叫postMethod.releaseConnection()時, 會呼叫connectionManager的releaseConnection方法。
注意:進入這個方法後會首先同步整個connectionPool(連線池)物件,這意味著,在多連線複用的時候頻繁的釋放連線,也是會有效能損耗的,同步整個connectionPool後連線的建立都會受影響。
然後開始歸還連線,歸還的方式很清晰:

1. 將Connection放到基於host的連線池的空閒連結串列中
    hostPool. freeConnections .add(conn);
2.將Connection放到整個全域性的connectionPool的空閒連結串列中
3. 將Connection從Reference Map中移除(Reference Map 後面單獨講解)
4. 將Connection加入到超時管理中去。
5. 將hostPool(host連線池)裡等待佇列的頭元素拿出來 傳送interrupt的訊號量。目的是 喚醒等待連線的執行緒。

到目前為止,有兩個點可以詳細說下
1. Reference Map的作用。
2.  等待連線的執行緒的處理方式。

首先說Reference Map,這個名字是我自己取的。它在MultiThreadedHttpConnectionManager  中的名字叫做:


 

在每次獲取連線和釋放連線的時候會將”連線“存入和移除。

注意: 這裡的”連線“ 已經不是Connection 而是用 WeakReference包裝過的Connection。

為什麼用WeakReference?

這裡的概念和ThreadLocal 中用WeakReference 包裝ThreadLocalMap中的Key一樣。 

目的是為了 在連線丟失時,HTTP client 失去了對“連線”(Connection)的強引用,該連線物件變成了弱引用物件,可以被GC掉。

所以,每次在獲取連線的時候 要將連線用WeakReference 包裝後放到REFERENCE_TO_CONNECTION_SOURCE 這個Map中,

每次釋放連線時,將它從REFERENCE_TO_CONNECTION_SOURCE 中移除,因為這個時候連線的管理由執行緒池使用強引用管理。

再說,等待連線的執行緒的處理方式

先看 獲取連線時的程式碼 和註釋  大部分程式碼被精簡了。 所以邏輯不通,看流程即可。

Java程式碼  收藏程式碼

  1. synchronized (connectionPool) {  
  2.         while (connection == null) {  
  3.             if (hostPool.freeConnections.size() > 0) {   
  4.                   //有執行緒池中有空閒的連線  
  5.                 connection = connectionPool.getFreeConnection(hostConfiguration);  
  6.             } else if ((hostPool.numConnections < maxHostConnections) && (connectionPool.numConnections < maxTotalConnections)) {  
  7.                   //沒有空閒連線,但是滿足前文的兩個條件 可以建立新的連線  
  8.                 connection = connectionPool.createConnection(hostConfiguration);   
  9.             } else if ((hostPool.numConnections < maxHostConnections) && (connectionPool.freeConnections.size() > 0)) {  
  10.                   //整個連線數 沒有到達最大,並且有空閒連線(其他host池中) 則刪除掉其他host中的連線,並且在當前host池子中建立新連線  
  11.                 connectionPool.deleteLeastUsedConnection();  
  12.                 connection = connectionPool.createConnection(hostConfiguration);  
  13.             } else {  
  14.                 //以上條件都不滿足, 只能將當前執行緒睡眠  
  15.                 try {   
  16.                   waitingThread = new WaitingThread();//建立一個執行緒包裝類  
  17.                   waitingThread.hostConnectionPool = hostPool;//指定所屬的host連線池  
  18.                   waitingThread.thread = Thread.currentThread();//將當前執行緒賦值             
  19.                   startWait = System.currentTimeMillis ();  
  20.                     hostPool.waitingThreads.addLast(waitingThread);//將執行緒包裝類 新增到host連線池的 等待列表中  
  21.                     connectionPool.waitingThreads.addLast(waitingThread);//將執行緒包裝類 新增到全域性連線池的 等待列表中  
  22.                     connectionPool.wait(timeToWait);//沉睡  
  23.                 } catch (InterruptedException e) {  
  24.                        //被打斷是檢查 布林變數interruptedByConnectionPool 確定是 HTTP 釋放連線後 主動打斷的,還是其他異常原因打斷  
  25.                        //是自己打斷的 catch住異常後什麼也不做,重新進入while迴圈中,嘗試獲取連線  
  26.                          if (!waitingThread.interruptedByConnectionPool) {  
  27.                              throw new IllegalThreadStateException("Interrupted while waiting in MultiThreadedHttpConnectionManager");  
  28.                          }  
  29.                 } finally {  
  30.                     if (!waitingThread.interruptedByConnectionPool) {  
  31.                         hostPool.waitingThreads.remove(waitingThread);  
  32.                         connectionPool.waitingThreads.remove(waitingThread);  
  33.                     }  
  34.                     if (useTimeout) {  
  35.                         endWait = System.currentTimeMillis ();  
  36.                         timeToWait -= (endWait - startWait);  
  37.                     }  
  38.                 }  
  39.             }  
  40.         }  
  41.     }  

釋放連線時

呼叫notifyWaitingThread 方法,結合上面的程式碼看:

Java程式碼  收藏程式碼

  1. public synchronized void notifyWaitingThread(HostConnectionPool hostPool) {  
  2.         // find the thread we are going to notify, we want to ensure that each  
  3.         // waiting thread is only interrupted once so we will remove it from  
  4.         // all wait queues before interrupting it  
  5.         WaitingThread waitingThread = null;  
  6.         // 取出 等待的執行緒後傳送     interrupt 訊號量,  
  7.         if (hostPool.waitingThreads.size() > 0) {  
  8.             waitingThread = ( WaitingThread) hostPool.waitingThreads.removeFirst();  
  9.             waitingThreads.remove(waitingThread);  
  10.         } else if (waitingThreads .size() > 0) {  
  11.             waitingThread = ( WaitingThread) waitingThreads.removeFirst();  
  12.             waitingThread.hostConnectionPool.waitingThreads.remove(waitingThread);  
  13.         }  
  14.         // 導致 獲取連線的那個方法中 捕獲異常  
  15.         // 注:interrupt 訊號量是一定會引起 interruptException的  
  16.         // 將interruptedByConnectionPool 設定為true 好標明 是 HTTP client 手動打斷的。 這是HTTP client對於等待執行緒喚醒方式的核心思路  
  17.         if (waitingThread != null) {  
  18.             waitingThread.interruptedByConnectionPool = true;  
  19.             waitingThread.thread.interrupt();  
  20.         }  
  21.     }  

上面兩端程式碼主要思路就是: 有空連線就直接用,沒有則沉睡等待喚醒。

其實用interrupt訊號量 會引起interruptException異常,通過catch住異常來處理,是比較粗暴的。

優雅的用 wait and notify的方式 就不需要catch異常,同樣能達到喚醒執行緒效果,而且很優雅。

MultiThreadedHttpConnectionManager  中對弱引用的使用

MultiThreadedHttpConnectionManager  類中 還有一個 ReferenceQueueThread類 是用來配合HttpConnectionWithReference(將連線用弱引用包裹後的物件)使用的


 

使用的方式是這樣:

1. 建立連線時,用弱引用包裹住Connection物件放到REFERENCE_TO_CONNECTION_SOURCE  中,目的是防止在連線丟失的時候Map中的這個HttpConnectionWithReference 物件變成弱引用,

     在GC回收時會被回收掉,防止記憶體洩露。

2. 首先明確的是,JVM會在HttpConnectionWithReference 被回收的時候,將他加入到REFERENCE_QUEUE 中。這是JAVA對於弱引用的規則。

3. 同時,在將HttpConnectionWithReference  放入Map時,啟動一個子執行緒 ReferenceQueueThread  去監聽 這個REFERENCE_QUEUE ,只要這個REFERENCE_QUEUE  有值(被GC回收的時候)

     立馬被取出來,將執行緒池可用連線的大小 -1 。

MultiThreadedHttpConnectionManager  使用弱引用 確保了

1. connection物件丟失時 記憶體的及時回收。

2. 搭配佇列和子執行緒確保,連線丟失後執行緒池中可用連線數的次數可以修改。

說到這裡,HTTP Client的MultiThreadedHttpConnectionManager  類的絕大部分分方法已經解釋完畢了。其中主要是省略掉了,傳送和讀取HTTP 報文的程式碼,沒有太多技巧,以規則解析出來即可。

總結:

1. 在單純的傳送請求的場景下,使用MultiThreadedHttpConnectionManager 來代替SimpleHTTPConnectionManger是可行的,並且MultiThreadedHttpConnectionManager 的連線池機制也會提高發送請求的效率,

2. 但是覺得不符合分散式應用間的藉口呼叫,原因很簡單,對每個host做了連線池,在一定情況下,這個限制是致命的,直接影響了介面的呼叫效率。嚴重影響呼叫的併發數。所以,在分散式應用的呼叫中不適合使用MultiThreadedHttpConnectionManager 。

MultiThreadedHttpConnectionManager類中幾個值得注意的點:

1. 連線的管理,特別是使用WeakReference包裝Connection物件,然後結合一個子執行緒和Queque去確保物件被回收時,可以連線數的增加。

2. 對於沒有連線可用時,使用使當前執行緒睡眠的,在釋放連線時 使用 interrupt訊號量 是等待執行緒恢復的處理方式

Java程式碼 

 收藏程式碼

  1. HttpClient client = new HttpClient();  
  2. HttpMethod method = new GetMethod("http://www.apache.org");  
  3. try {  
  4.   client.executeMethod(method);  
  5.   byte[] responseBody = null;  
  6.   responseBody = method.getResponseBody();  
  7. } catch (HttpException e) {  
  8.   // TODO Auto-generated catch block  
  9.   e.printStackTrace();  
  10. } catch (IOException e) {  
  11.   // TODO Auto-generated catch block  
  12.   e.printStackTrace();  
  13. }finally{  
  14.   method.releaseConnection();  
  15. }  


大部分人使用HttpClient都是使用類似上面的事例程式碼,包括Apache官方的例子也是如此。最近我在使用HttpClient是發現一次迴圈傳送大量請求到伺服器會導致APACHE伺服器的連結被佔滿,後續的請求便排隊等待。 
我伺服器端APACHE的配置 

Java程式碼 

 收藏程式碼

  1. Timeout 30  
  2. KeepAlive On   #表示伺服器端不會主動關閉連結  
  3. MaxKeepAliveRequests 100  
  4. KeepAliveTimeout 180   


因此這樣的配置就會導致每個連結至少要過180S才會被釋放,這樣在大量請求訪問時就必然會造成連結被佔滿,請求等待的情況。 
在通過DEBUH後發現HttpClient在method.releaseConnection()後並沒有把連結關閉,這個方法只是將連結返回給connection manager。如果使用HttpClient client = new HttpClient()例項化一個HttpClient connection manager預設實現是使用SimpleHttpConnectionManager。SimpleHttpConnectionManager有個建構函式如下 

Java程式碼 

 收藏程式碼

  1. /** 
  2.  * The connection manager created with this constructor will try to keep the  
  3.  * connection open (alive) between consecutive requests if the alwaysClose  
  4.  * parameter is set to <tt>false</tt>. Otherwise the connection manager will  
  5.  * always close connections upon release. 
  6.  *  
  7.  * @param alwaysClose if set <tt>true</tt>, the connection manager will always 
  8.  *    close connections upon release. 
  9.  */  
  10. public SimpleHttpConnectionManager(boolean alwaysClose) {  
  11.     super();  
  12.     this.alwaysClose = alwaysClose;  
  13. }  


看方法註釋我們就可以看到如果alwaysClose設為true在連結釋放之後connection manager 就會關閉鏈。在我們HttpClient client = new HttpClient()這樣例項化一個client時connection manager是這樣被例項化的 

Java程式碼 

 收藏程式碼

  1. this.httpConnectionManager = new SimpleHttpConnectionManager();  


因此alwaysClose預設是false,connection是不會被主動關閉的,因此我們就有了一個客戶端關閉連結的方法。 
方法一: 
把事例程式碼中的第一行例項化程式碼改為如下即可,在method.releaseConnection();之後connection manager會關閉connection 。 

Java程式碼 

 收藏程式碼

  1. HttpClient client = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) );  


方法二: 
例項化程式碼使用:HttpClient client = new HttpClient(); 
在method.releaseConnection();之後加上 

Java程式碼 

 收藏程式碼

  1. ((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();  


shutdown原始碼很簡單,看了一目瞭然 

Java程式碼 

 收藏程式碼

  1. public void shutdown() {  
  2.     httpConnection.close();  
  3. }  


方法三: 
例項化程式碼使用:HttpClient client = new HttpClient(); 
在method.releaseConnection();之後加上 
client.getHttpConnectionManager().closeIdleConnections(0);此方法原始碼程式碼如下: 

Java程式碼 

 收藏程式碼

  1. public void closeIdleConnections(long idleTimeout) {  
  2.     long maxIdleTime = System.currentTimeMillis() - idleTimeout;  
  3.     if (idleStartTime <= maxIdleTime) {  
  4.         httpConnection.close();  
  5.     }  
  6. }  


將idleTimeout設為0可以確保連結被關閉。 
以上這三種方法都是有客戶端主動關閉TCP連結的方法。下面再介紹由伺服器端自動關閉連結的方法。 
方法四: 
程式碼實現很簡單,所有程式碼就和最上面的事例程式碼一樣。只需要在HttpMethod method = new GetMethod("http://www.apache.org");加上一行HTTP頭的設定即可 

Java程式碼 

 收藏程式碼

  1. method.setRequestHeader("Connection", "close");  


看一下HTTP協議中關於這個屬性的定義: 
HTTP/1.1 defines the "close" connection option for the sender to signal that the connection will be closed after completion of the response. For example, 
       Connection: close 
現在再說一下客戶端關閉連結和伺服器端關閉連結的區別。如果採用客戶端關閉連結的方法,在客戶端的機器上使用netstat –an命令會看到很多TIME_WAIT的TCP連結。如果伺服器端主動關閉連結這中情況就出現在伺服器端。 
參考WIKI上的說明http://wiki.apache.org/HttpComponents/FrequentlyAskedConnectionManagementQuestions 
The TIME_WAIT state is a protection mechanism in TCP. The side that closes a socket connection orderly will keep the connection in state TIME_WAIT for some time, typically between 1 and 4 minutes. 
TIME_WAIT的狀態會出現在主動關閉連結的這一端。TCP協議中TIME_WAIT狀態主要是為了保證資料的完整傳輸。具體可以參考此文件: 
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-2.html#ss2.7 
另外強調一下使用上面這些方法關閉連結是在我們的應用中明確知道不需要重用連結時可以主動關閉連結來釋放資源。如果你的應用是需要重用連結的話就沒必要這麼做,使用原有的連結還可以提供效能。

方法二: 
例項化程式碼使用:HttpClient client = new HttpClient(); 
在method.releaseConnection();之後加上 
Java程式碼 
((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown();  

((SimpleHttpConnectionManager)client.getHttpConnectionManager()).shutdown(); 
shutdown原始碼很簡單,看了一目瞭然 
Java程式碼 
public void shutdown() {   
    httpConnection.close();   
}  

public void shutdown() { 
    httpConnection.close(); 


方法二中的httpConnection.close();這裡沒有引數麼? 
httpConnection為預設全域性的那個連線? 

HttpClient client = new HttpClient(); 如果這樣進行例項化,預設使用SimpleHttpConnectionManager作為connection manager,SimpleHttpConnectionManager沒有連線池,只管理一個連線

建立連線

        在HttpClient中使用多執行緒的一個主要原因是可以一次執行多個方法。在執行期間,每一個方法都使用一個HttpConnection例項。由於在同一時間多個連線只能安全地用於單一執行緒和方法和有限的資源,我們就必須確保連線分配給正確的方法。而MultiThreadedHttpConnectionManager完全可以代替我們完成這一項工作,這樣我們就不必去考慮多執行緒帶來安全的問題。
MultiThreadedHttpConnectionManager connectionManager =
                 new MultiThreadedHttpConnectionManager();
          HttpClient client = new HttpClient(connectionManager);

以上程式碼中的HttpClient就在多執行緒中執行多個方法了。當我們再次呼叫httpClient.executeMethod()方法時,就會去Connection Manager中去請求HttpConneciton的例項,這樣就避免了執行緒安全問題,因為HttpClient已經幫我們做了。

釋放連線

          Connection Management比較重要的是當連線不再使用時,一定要手動釋放。這樣做的原因是HttpClient不能夠確定哪個方法不被使用,哪個方法還在使用。這是因為Response body不是由HttpClient來自動讀取其資料的,而是由使用HttpClient的應用程式來完成的。當讀取Response的資料是時,必須使用此方法的連線。這樣,在Response的資料在讀取前,HttpClient是沒有釋放連線的。所有這就要求在讀取完Response的資料後,應用程式及時的使用releaseConnection()方法來釋放連線。特別注意,無論執行的方法或是否也不例外被丟擲。對於每一個HttpClient.executeMethod方法必須有一個method.releaseConnection ( )來釋放連線。

重用HttpClient例項

          一般說來,建議一個通訊元件,甚至說一個應用軟體就始終維持一個HttpClient物件例項存在。但是如果你的應用很稀罕才用到它,而且還不允許這麼一個例項一直存在,那麼,這裡強烈建議,一定要顯式地shut down 它的MultiThreadedHttpConnectionManager 。這樣做是確保連線池裡的Connection得到釋放。 

HttpMethod併發執行

         如果應用程式邏輯允許併發執行多個HTTP請求,(例如對多個伺服器的多個併發請求,或對同一個伺服器代表不同使用者身份的多個請求) ,應用程式可以為每一個HTTP session開啟一個專門的執行緒,這樣的設計自然將帶來顯著的效能提升。 而當使用一個執行緒安全的連線管理器MultiThreadedHttpConnectionManager 時,HttpClient能保證執行緒安全。這樣,多個執行緒可以共享這麼一個執行緒安全的HttpClient例項。請注意,應用程式的每個各自執行的執行緒必須使用各自的HttpMethod例項;並且可配置各自的HttpState例項和/或HostConfiguration例項(代表一個特定的會話狀態和主機配置)。這個共享的HttpClient和其標配的MultiThreadedHttpConnectionManager將為各執行緒帶來最高的效能。

使用流來發送和接收資料

        HttpClient同時支援Stream和String/byte[]兩種方式來發送和接受資料,但是由於String/byte[]的方式會造成記憶體中有一份資料的拷貝或快取,那麼當請求或應答報文比較大,或者在高併發的應用中,使用String/byte[]就會造成額外的記憶體開銷,所以使用流的方式來傳輸資料是更好的選擇。

HttpClient的三種超時說明

/* 從連線池中取連線的超時時間 */
ConnManagerParams.setTimeout(params, 1000);
/* 連線超時 */
HttpConnectionParams.setConnectionTimeout(params, 2000);
/* 請求超時 */
HttpConnectionParams.setSoTimeout(params, 4000);
 
第一行設定ConnectionPoolTimeout:這定義了從ConnectionManager管理的連線池中取出連線的超時時間,此處設定為1秒。
第二行設定ConnectionTimeout:  這定義了通過網路與伺服器建立連線的超時時間。Httpclient包中通過一個非同步執行緒去建立與伺服器的socket連線,這就是該socket連線的超時時間,此處設定為2秒。
第三行設定SocketTimeout:    這定義了Socket讀資料的超時時間,即從伺服器獲取響應資料需要等待的時間,此處設定為4秒。
以上3種超時分別會丟擲ConnectionPoolTimeoutException,ConnectionTimeoutException與SocketTimeoutException。

相關推薦

httpclient請求 java.net.BindException: Address already in use

參考文件: http://liuinsect.iteye.com/blog/1886237 http://www.iteye.com/topic/234759 http://blog.csdn.net/kobejayandy/article/details/169212

tomcat啟動java.net.BindException: Address already in use: bind錯誤解決方案

繼續學習Spring Boot,我新建了一個Spring Boot的專案 ,建好專案之後,進行測試時,出現瞭如下錯誤: java.net.BindException: Address already in use: bind at sun.nio.ch.Net.bind0

錯:java.net.bindexception: address already in use: jvm_bind:8080

lips RoCE ava ESS build 命令 ips 顯示 exception 原因:8080端口被占用 這說明80端口(該端口是Tomcat的監聽端口)已經被其他程序占用,先用命令提示符 " netstat -ano " 命令顯示端口狀態,再在結果中找到端口,然

錯:java.net.bindexception: address already in use: jvm_bind

exceptio exc 原因 報錯 pan use ddr net exce 原因:8080端口被占用 報錯:java.net.bindexception: address already in use: jvm_bind

jmeter壓力測試錯:java.net.BindException: Address already in use: connect

jmeter壓力測試報錯:java.net.BindException: Address already in use: connect 最近在實現介面壓力測試的時候遇到這樣的一個問題 當執行緒數持續上升到一個點的時候,執行指令碼的時候有很多報錯,如圖: java.net.BindExc

啟動springboot時,控制檯java.net.BindException: Address already in use: bind,但仍然能顯示想要的結果

java.net.BindException: Address already in use: bind這個是埠被佔用(例如8080埠被其他程序佔用),所以需要關掉佔用我們埠的那個程序,使用cmd 輸入命令列--netstat -ano就會得到佔用我們埠的程序的pid 然後輸

jetty 啟動錯: java.net.BindException: Address already in use

開始新的IDE和容器之旅,IDEA + Jetty,啟動jetty的時候報錯: java.net.BindException: Address already in use: 原因:埠被佔用。 查看了一下,Apache和Maven控制檯開著,於是先關閉Apache,再試,還

Exception in thread "main" java.net.BindException: Address already in use: JVM_Bind

next style exception void println clas can color imp 1 import java.io.PrintStream; 2 import java.net.Socket; 3 import java.net.Serve

jmeter 運行腳本報錯 java.net.BindException: Address already in use

1.7 pan exception window mage dex cpi 並且 聚合 在win下跑jmeter時,在聚合報告中出現錯誤。打開日誌文件(前提是將日誌寫入了指定文件) 發現報錯的原因為:java.net.BindException: Address alrea

java.net.BindException: Address already in use: JVM_Bind

led .net 錯誤提示 ready The eclips jms failed index 在myeclipse中,啟動JBoss4.2.3,出現地址綁定異常,在server.xml中改了8080端口號,也沒有用,一樣報這個錯?22:38:09,766 WARN [S

JMeter Exception: java.net.BindException: Address already in use: connect(轉)

轉自:http://twit88.com/blog/2008/07/28/jmeter-exception-javanetbindexception-address-already-in-use-connect/ JMeter異常:java.net.BindException:地址已在使用中:connect

idea java java.net.BindException "Address already in use: JVM_Bind

啟動tomcat時,報錯:java.net.BindException "Address already in use: JVM_Bind 127.0.0.1:55486 解決:報錯資訊意思是:地址已經被使用。大概就是說這個地址和埠:127.0.0.1:23480已經被其他

Caused by: java.net.BindException: Address already in use: no further information

錯誤 Error:Abnormal build process termination: "C:\Program Files\Java\jdk1.8.0_171\bin\java" -Xmx700m -Djava.awt.headless=true -Djava.endorsed.

JSTUN 出現 java.net.BindException: Address already in use: Cannot bind

使用JSTUN,進行NAT穿越的時候,總是出現java.net.BindException: Address already in use: Cannot bind 換其他機器測試,沒有問題。只有自己機器執行出現這個問題。 開啟JSTUN原始碼,檢視DiscoveryTes

java.net.BindException: Address already in use: JVM_Bind :1099

嚴重: Failed to initialize end point associated with ProtocolHandler ["ajp-bio-1099"] java.net.BindException: Address already in use: JVM_B

【解決】java.net.BindException: Address already in use: JVM_Bind

錯誤 嚴重: StandardServer.await: create[8005]: java.net.BindException: Address already in use: JVM_Bind at java.net.DualSta

埠被佔用的情況 java.net.BindException: Address already in use: bind

IDEA+jetty啟動專案control層時,報java.net.BindException: Address already in use: bind解決方案:開啟cmd netstat ano|findstr 8080taskkill -pid 6044 -f即可

80端口占用異常解決方法java.net.BindException: Address already in use: JVM_Bind:80(或8080)

pid 異常解決 exc == protocol nbsp catalina int tcp 1:Tomcat(或其他Web容器)啟動時控制臺報錯如下示: 2007-8-2 15:20:43 org.apache.coyote.http11.Http11Protocol

java.net.BindException: Address already in use: JVM_Bind :8001解決辦法

嚴重: Failed to initialize end point associated with ProtocolHandler ["http-bio-8001"] java.net.BindException: Address already in use: JVM_

Unable to open debugger port (127.0.0.1:13249): java.net.BindException "Address already in use: JVM_Bind"

ddr 更新 java image cat logs exce blog 一點 這個問題比較簡單一點,Tomcat的端口被占用了,我使用的是IDEA裏的一個熱部署插件JReble,更新了IDEA之後就發現端口被占用了,可能我電腦沒有重啟過吧, 一直被占用著,所以解決方法就