為了提高httpwebrequest的執行效率,查到了一些如下設置 request.ServicePoint.Expect100Continue = false; request.ServicePoint.UseNagleAlgorithm = false; request.ServicePoint.ConnectionLimit = 65500; request.AllowWriteStreamBuffering = false; request.Proxy = null; 然后就看到了如下相關的一些文章,記錄下來: 轉:C#中HttpWebRequest的GetRequestStream執行的效率太低,甚至偶爾死掉 用C#模擬網頁登陸,其中去請求幾個頁面,會發起對應的http的請求request,其中keepAlive設置為true,提交請求后,然后會有對應的response: resp = (HttpWebResponse)req.GetResponse(); 之前的多次調試,一直都是可以正常獲得對應的response,然后讀取html頁面的。 但是后來幾次的調試,在沒有改變代碼的前提下,結果GetResponse卻始終會超時死掉。 【解決過程】 1.默認request的timeout是1000000毫秒=100秒,都會超時,手動改為10秒,因此就更容易超時了,無法解決問題。 2.將http的request的keepAlive設置為false,問題依舊。 3.去參考:c# request.GetResponse();超時問題的解決,和HttpWebRequest多線程性能問題,請求超時的錯誤, 去把前面共4次的httprequest,每次都增加對應的: resp = null; 。。。 if (resp != null) { resp.Close(); } if (req != null) { req.Abort(); } 結果還是沒解決問題。 4. 同樣參考:HttpWebRequest多線程性能問題,請求超時的錯誤, 去嘗試關於DefaultConnectionLimit的設置,改為為10: System.Net.ServicePointManager.DefaultConnectionLimit = 10; 問題依舊。 5.又去測試了下,關於response.Close() 也是沒解決問題。 6. 最后無意間,索性不抱希望的,再次DefaultConnectionLimit設置為更大的值50: System.NET.ServicePointManager.DefaultConnectionLimit = 50; 試了試,結果就解決超時的問題了。 然后才搞懂原因。 之前默認設置為2,后來改為10,都沒有解決問題的原因在於,當前有很多個http的連接,沒有被關閉掉, 而這些keepalive的連接,都是 由於代碼中,對於前面多個request。其都是keepalive為true,以及多個response也沒有close, 而之前調試了很多次了,所以,此時已經存在了很多個alive的http連接了,已經超過了10個了,所以前面設置了DefaultConnectionLimit 為10,也還是沒用的。 而改為50,才夠用。 【總結】 此處GetResponse超過的原因是,當前存在太多數目的alive的http連接(大於10個),所以再次提交同樣的http的request,再去GetResponse,就會超時死掉。 解決辦法就是,把DefaultConnectionLimit 設置為一個比較大一點的數值,此數值保證大於你當前已經存在的alive的http連接數即可。 【經驗總結】 以后寫http的request代碼,如果不是必須的要keepalive的,那么就要設置KeepAlive為false: req.KeepAlive = false; 以及做對應的收尾動作: if (resp != null) { resp.Close(); } if (req != null) { req.Abort(); } 【后記 2012-03-01】 又偶爾遇到一次,DefaultConnectionLimit已經是200了,足夠大了,但是GetResponse和GetRequestStream,還是會超時死掉的問題,具體是什么原因導致的還不是很清楚,但是經過折騰,參考: HttpWebResponse’s GetResponse() hangs and timeouts 在: req = (HttpWebRequest)WebRequest.Create(constSkydriveUrl); setCommonHttpReqPara(ref req); resp = (HttpWebResponse)req.GetResponse(); 之前,添加一句垃圾回收: System.GC.Collect(); 然后就解決了GetResponse的超時問題,並且后面的GetRequestStream也同時可以正常工作,不超時了。 所以,看起來像是當前系統由於調試多次,並且HttpWebRequest和HttpWebResponse都是沒有正常去Close的,可能會殘留一些http的鏈接,然后就可能影響到了后續對於http的使用,垃圾回收后,估計就把殘余的http相關資源釋放了,然后http就可以正常工作了。 【總結】 對於GetResponse或GetRequestStream超時死掉的原因,可能是: 1.DefaultConnectionLimit是默認的2,而當前的Http的connection用完了,導致后續的GetResponse或GetRequestStream超時死掉 ==>> 默認系統只支持同時存在2個http的connection ==>> 使用HttpWebRequest之后如果沒有close,則會占用1個http的connection,所以如果超過2次使用HttpWebRequest而沒有close,那么就用完系統的http的connection,之后再去使用HttpWebRequest,GetResponse就會死掉 解決辦法: 辦法1: 每次使用完HttpWebRequest,使用 1 2 req.Close(); req=null; 去關閉對應的http connection 最好對應的HttpWebResponse也要close: 1 2 resp.Close(); resp = null; 方法2: 修改DefaultConnectionLimit的值,改為足夠大,比如: 1 System.Net.ServicePointManager.DefaultConnectionLimit = 200; 2.系統中Http相關的資源沒有正確釋放,導致后續GetResponse或GetRequestStream超時死掉 就像我此處遇到的,可能是之前調用http相關函數,沒有正確完全釋放資源,導致雖然DefaultConnectionLimit給了足夠大,但是還是會死掉,此時在http請求代碼之前去做一次垃圾回收,則后續http的GetResponse或GetRequestStream就正常了,就不會超時死掉了。 參考代碼如下: 1 2 3 4 5 System.GC.Collect(); req = (HttpWebRequest)WebRequest.Create(constSkydriveUrl); setCommonHttpReqPara(ref req); resp = (HttpWebResponse)req.GetResponse(); 3.Http的GET請求時,不要手動設置ContentLength的值 這個是參考這里:HttpWebRequest.GetResponse() hangs the second time it is called而記錄於此的,也許有人是此原因,所以可供參考一下。 即Http的GET請求,不要添加類似如下的代碼: 1 2 if (m_contentLength > 0) httpWebRequest.ContentLength = m_contentLength; 不要去手動修改對應的ContentLength的值,C#的http相關庫函數,會自動幫你計算的。 注:POST方法中,的確是要手動填充數據和算出數據大小,然后手動給ContentLength賦值的。 4.其他可能的一些原因 (1)關於KeepAlive的問題 如果Http的請求,是設置了KeepAlive=true的話,那么對應的http的connection會和服務器保持連接的。 所以如果上述辦法都不能解決超時的問題,可以嘗試將keepAlive設置為false試試,看看能否解決。 (2)關於Sleep 有些人好像是通過在http請求前,加了對應的Sleep,結果解決了此問題。需要的人,也可以試試。 (3)HttpWebRequest的Timeout 一般來說,既然超時了,往往是由於錯誤使用函數或者網絡有問題導致的,所以實際上此處對於有些人去把HttpWebRequest的Timeout的值改的更大,往往都是沒用的。 只不過,萬一是由於網絡響應慢而導致超時,那么倒是可以嘗試,將HttpWebRequest的Timeout的值改為更大。 (其中HttpWebRequest的Timeout默認的值是100,000 milliseconds ==100 seconds)