C#HttpClient - 我可以强制关闭连接吗?

时间:2015-12-21 18:28:17

标签: c# iis dotnet-httpclient

我们遇到的问题是客户在使用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秒超时后无法发回任何数据?

3 个答案:

答案 0 :(得分:2)

我终于能够通过使用原始套接字来复制问题,这是很多工作。让IIS记录已取消的请求的方法是在下面的代码中执行以下操作:

  1. 请勿发送Connection: Close
  2. 请勿致电Socket.Dispose()
  3. 这是最终的工作代码,希望其他人会觉得这很有用:

    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();
                }
            }
    

答案 1 :(得分:1)

您可能会遇到非常低的超时设置。如果将其设置为足够短的时间,客户端将关闭连接,尽管服务器仍尝试返回数据。

如果这不能重现问题,您还可以在服务点管理器上查看并发性和属性“UseNagleAlgorithm”。此属性为true,尝试在同一TCP包中对几个小的http请求进行pigiback。它是一个带有保护程序的乐队,但会导致客户端超时,因为操作系统延迟通过套接字发送数据,直到它收集了足够的数据。

答案 2 :(得分:0)

您是否尝试过在响应对象上调用Dispose?

看看这篇文章: Force connection to close with HttpClient in WCF