Search code examples
c#.nethttptcpnetworkstream

Each http request takes 60 seconds Why?


Below is the code block illustrating how I can send an HTTP request using TCP and network stream. However, regardless of any filtering applied, each request consistently consumes an average of 60 seconds. Whether a single data or a thousand arrive, the delay remains constant. Why does it persist at 60 seconds? Is there no option to shorten this period or a setting to fetch data immediately without waiting?

// Specify the server and port
string server = "xxx.com";
int port = 80;

// Specify the HTTP request
string httpRequest = "POST /ApiPrefixNameHere/ControllerNameHere/ActionNameHere HTTP/1.1\r\nHost: xxx.com\r\naccept: text/plain\r\nContent-Type: application/json-patch+json\r\nContent-Length: 27\r\n\r\n{\"ParameterNameHere\":\"1580\"}";

// Create a TcpClient
using (TcpClient tcpClient = new())
{
    await tcpClient.ConnectAsync(server, port);

    using (NetworkStream networkStream = tcpClient.GetStream())
    using (StreamWriter writer = new(networkStream, Encoding.ASCII))
    using (StreamReader reader = new(networkStream, Encoding.ASCII))
    {
        // Send the HTTP request
        await writer.WriteAsync(httpRequest);
        await writer.FlushAsync();

        // Read the response
        string response = await reader.ReadToEndAsync();

        // Display the response
        Console.WriteLine("Response: " + response);
    }
}

I'm not well-versed in these older methods. I attempted strategies like NoDelay() and various timeout configurations, but none proved effective.

Thank you in advance for your assistance.


EDIT after @jonskeet's answer


// add `Connection: close`
string httpRequest = "POST /ApiPrefixNameHere/ControllerNameHere/ActionNameHere HTTP/1.1\r\nHost: xxx.com\r\naccept: text/plain\r\nContent-Type: application/json-patch+json\r\nConnection: close\r\nContent-Length: 28\r\n\r\n{\"ParameterNameHere\":\"1580\"}";


Solution

  • I can see two problems with the specific code you've got, but more generally I'd strongly encourage you not to use TcpClient for HTTP requests unless you absolutely have to. Both of these problems would have been avoided if you'd used HttpClient, I believe.

    Firstly, you're specifying a header of Content-Length: 27 - but then you're sending 28 bytes of content, as far as I can see. Maybe that's only a problem in the sample code, but it does demonstrate how brittle this approach is.

    Secondly, you're calling StreamReader.ReadToEnd, which means you're waiting for the connection to be closed. You're not closing the connection, which means you're expecting the server to close it. But in HTTP/1.1 (which is the version you're specifying), the default behavior is to keep the connection alive. So I strongly suspect that what you're seeing is the server immediately send a response - and then time out after a minute waiting for the next request.

    To avoid this, you can send a header of Connection: close... or preferably, use HttpClient so you don't need to know details of HTTP.