我很難弄清楚在使用.NET的HttpWebRequest類調用遠程服務器(特別是REST Web服務)時是否有辦法處理潛在的連接問題。從我的調查中,WebClient類的行爲是相同的,這是有點期待的,因爲它似乎只提供了一個更簡單的HttpWebRequest接口。HttpWebRequest如何處理(過早)關閉底層TCP連接?
爲了模擬目的,我編寫了一個非常簡單的HTTP服務器,該服務器的行爲不符合HTTP 1.1 RFC。它所做的是接受客戶端連接,然後發送適當的HTTP 1.1頭文件和「Hello World!」。有效載荷返回給客戶端,並關閉套接字,線程接受服務器端的客戶端連接,如下所示:
private const string m_defaultResponse = "<html><body><h1>Hello World!</h1></body></html>";
private void Listen()
{
while (true)
{
using (TcpClient clientConnection = m_listener.AcceptTcpClient())
{
NetworkStream stream = clientConnection.GetStream();
StringBuilder httpData = new StringBuilder("HTTP/1.1 200 OK\r\nServer: ivy\r\nContent-Type: text/html\r\n");
httpData.AppendFormat("Content-Length: {0}\r\n\r\n", m_defaultResponse.Length);
httpData.AppendFormat(m_defaultResponse);
Thread.Sleep(3000); // Sleep to simulate latency
stream.Write(Encoding.ASCII.GetBytes(httpData.ToString()), 0, httpData.Length);
stream.Close();
clientConnection.Close();
}
}
}
由於該HTTP 1.1默認情況下保持連接活着的HTTP 1.1 RFC狀態和服務器必須發送一個「Connection:Close」響應頭,如果它想關閉一個連接,這是客戶端的意外行爲。客戶端使用的HttpWebRequest以下列方式:
private static void SendRequest(object _state)
{
WebResponse resp = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.0.32:7070/asdasd");
request.Timeout = 50 * 1000;
DateTime requestStart = DateTime.Now;
resp = request.GetResponse();
TimeSpan requestDuration = DateTime.Now - requestStart;
Console.WriteLine("OK. Request took: " + (int)requestDuration.TotalMilliseconds + " ms.");
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.Timeout)
{
Console.WriteLine("Timeout occurred");
}
else
{
Console.WriteLine(ex);
}
}
finally
{
if (resp != null)
{
resp.Close();
}
((ManualResetEvent)_state).Set();
}
}
上述方法是通過ThreadPool.QueueUserWorkItem(waitCallback,stateObject)排隊。 ManualResetEvent用於控制排隊行爲,以免整個線程池被等待任務填滿(因爲HttpWebRequest隱式使用工作線程,因爲它在內部異步執行以實現超時功能)。
所有這一切的問題是,一旦HttpWebRequest的底層ServicePoint的所有連接都被「用完」(即由遠程服務器關閉),就不會有新的連接打開。如果ServicePoint的ConnectionLeaseTimeout設置爲較低值(10秒),也沒有關係。一旦系統進入此狀態,它將不再正常工作,因爲它不會自動重新連接,並且所有後續的HttpWebRequests都會超時。現在的問題是,如果有辦法通過在某些條件下銷燬ServicePoint或關閉解除綁定連接來解決這個問題(我沒有任何運用ServicePoint.CloseConnectionGroup()的方法,那麼該方法也沒有相應的文檔記錄正確使用它)。
有沒有人有任何想法我可以如何解決這個問題?