簡體   English   中英

C#HttpClient - 我可以強制關閉連接嗎?

[英]C# HttpClient - can I force close the connection?

我們遇到的問題是客戶在使用API​​並在完成之前取消請求。 我們認為他們也在關閉連接,因此請求不會寫入IIS日志。 我正在嘗試創建一個運行器來復制此行為。 我無法弄清楚的是如何強制關閉連接以便服務器無法發回數據?

這是我目前的代碼:

 private static async Task RunMe()
    {

        var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);

        using (var client = new HttpClient())
        {
            try
            {
                client.DefaultRequestHeaders.ConnectionClose = true;
                client.DefaultRequestHeaders.Add("x-apikey", "some key");
                Console.WriteLine("making request");
                using (var response = await client.GetAsync("https://foo.com/api/apitest/testcancel", cts.Token))
                {
                    var result = await response.Content.ReadAsStringAsync();
                    Console.WriteLine($"Request completed: {result}");
                }
            }
            finally
            {                    
                client.CancelPendingRequests();
                Console.WriteLine("about to dispose the client");
                client.Dispose();
            }
        }
    }
}

代碼在5秒后正確取消請求,但IIS似乎仍在API調用完成后發送回數據(設置為10秒)。

如何關閉連接,以便IIS在5秒超時后無法發回任何數據?

我終於能夠通過使用原始套接字來復制問題,這是很多工作。 讓IIS記錄已取消的請求的方法是在下面的代碼中執行以下操作:

  1. 不要發送Connection: Close
  2. 不要調用Socket.Dispose()

這是最終的工作代碼,希望其他人會發現這很有用:

private static void SocketTime(int readTimeout, Random random)
        {
            var ip = IPAddress.Parse("127.0.0.1");
            const int hostPort = 80;

            var hostep = new IPEndPoint(ip, hostPort);
            var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            sock.Connect(hostep);
            var uniqueID = random.Next().ToString();
            var get = $"GET http://localhost/api/apitest/testcancel/{uniqueID} HTTP/1.1\r\n" +
                      "x-apikey: somekey\r\n" +
                      "Host: foo.com\r\n" +
                      "Connection: Close\r\n" +
                      "\r\n";


            var getBytes = Encoding.UTF8.GetBytes(get);
            sock.ReceiveTimeout = readTimeout;
            sock.Send(getBytes);

            var responseData = new byte[1024];
            try
            {
                var bytesRead = sock.Receive(responseData);
                var responseString = new StringBuilder();
                while (bytesRead != 0)
                {
                    responseString.Append(Encoding.ASCII.GetChars(responseData), 0, bytesRead);
                    bytesRead = sock.Receive(responseData);
                }
                Console.WriteLine($"SUCCESS => Unique ID = {uniqueID}, Timeout = {readTimeout}");
            }
            catch (SocketException e)
            {
                if (e.SocketErrorCode == SocketError.TimedOut)
                {
                    Console.WriteLine($"FAIL => Unique ID = {uniqueID}, Timeout = {readTimeout}");
                }
                else
                {
                    Console.WriteLine("UNHNALDED ERROR: " + e.Message);
                }

            }
            finally
            {
                sock.Dispose();
            }
        }

您可能會遇到非常低的超時設置。 如果將其設置為足夠短的時間,客戶端將關閉連接,盡管服務器仍嘗試返回數據。

如果這不能重現問題,您還可以在服務點管理器上查看並發性和屬性“UseNagleAlgorithm”。 此屬性為true,嘗試在同一TCP包中對幾個小的http請求進行pigiback。 它是一個帶有保護程序的樂隊,但會導致客戶端超時,因為操作系統延遲通過套接字發送數據,直到它收集了足夠的數據。

您是否嘗試過在響應對象上調用Dispose?

看看這篇文章: 在WCF中強制連接關閉HttpClient

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM