Click here to Skip to main content
15,884,237 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
Hello,

I'm developing a simple HTTP client in C++ (using VS2010) and I'm using an apache located at localhost for testing.

While the send'ing code workes like a charm, the recv takes up to 6-7 seconds to receive the whole message (500 bytes or so).

The actual question: how come is recv so slow? (I'm also setting TCP_NODELAY on my socket)

My implementation of the receiving routine:
C++
int HttpClient::_receive()
{
    char buffer[1024];
    int  iReceivedBytes = 0;

    // init the buffer to an empty string
    buffer[0] = 0;

    while(1)
    {
        iReceivedBytes = recv(m_socket, buffer, 1024, 0);
        if (iReceivedBytes > 0)
        {
            // m_response is a member std::string
            m_response.append(buffer, iReceivedBytes);
        } else
           break;
    }

    // parse message
    return _parseMessage();
}


Edit: When testing the apache with a browser it takes less than 1 second to perform the same request.

Thanks,
Alex
Posted
Updated 24-Aug-12 8:09am
v2
Comments
JackDingler 24-Aug-12 12:48pm    
Is the webserver taking that long to respond?

Or do you know?
Alex Culea 24-Aug-12 14:07pm    
No, the webserver is not the culprit in this case. It takes my browser less than 1 sec to load the same message (a short .htm file). Also it's noticeable when debugging as I step through code that recv blocks.
JackDingler 24-Aug-12 14:31pm    
Recv is a blocking call.

Use select() to see if data is waiting, before making the call.
Alex Culea 24-Aug-12 16:04pm    
While it is my intention for recv to block (is running in a separate thread), the actual problem is that it blocks for too long. I updated the code to use the select function and still nothing. Also, when I test the code on a remote server (google.com) the recv function blocks until I stop debugging. Could it have anything to do with the socket creation code? Btw, thanks for your input.
JackDingler 24-Aug-12 16:15pm    
Oh... that explains a bit...

The debugger blocks/slows threads while you're stepping through code. It can be a bit tricky to debug multi-threaded applications.

Try using TRACE statements to debug around the recv call rather than stepping in with the debugger.
then the code can run at full speed and you'll see the reports in the output window.

1 solution

TCP_NODELAY has effect only on sending, it doesn do anything with recv(). It turns on/off the nagle alorithm that makes bandwith usage better if you call send() on a socket often with small data sizes.

Here is my guess: You exit your infinite loop when recv() returns zero or negative. This is bad for two reasons.
A negative values means that something very bad happened and you should handle it specially. Zero is returned by recv() when the connection has been shut down on the other side - for example because the http server has closed its socket. Your problem is probably that you are waiting for this socket close event and you should not rely on it. If you are using HTTP 1.0 header in your request then your http session isnt using permanent connection, in case of HTTP 1.1 its the same only if you use the Connection: close[^] header in your request. But even if the connection of http session isn't permanent noone guarantees for you that the server closes the connection after sending the data. To check if your problem is what I described do the following: After every recv() log out the totoal number of bytes received. Also print a log message when you break out from your loop. I guess you receive all data in less than a second, but the break executes only after 5 seconds when the server closes the connection.

To avoid the previous issues your http client should work like this: Currently you read the whole packet including the header and the payload and you interpret it just after this. Instead this you should read only the header part first - its easy to detect it, a double newline (CRLF) - and then you should parse/interpret the header. If the response doesnt use chunked transfer encoding (indicated by the "Transfer-Encoding: chunked" header in the response) then the payload of the HTTP response will have fixed size indicated by the "Content-Length" header field. I guess you dont want to handle chunked transfer encoding so you will look for Content-Length headers instead. So you read the header and found out the size of the payload. After this you know how many bytes following the header - you just read that out from the socket and the close the connection.
 
Share this answer
 
v2
Comments
Alex Culea 24-Aug-12 16:51pm    
The "Connection: Close" entry did the job. The server was keeping the connection alive. The code posted above is a bad example of coding but this was not the purpose of the question. Thank you very much!
pasztorpisti 24-Aug-12 16:53pm    
You are welcome!
JackDingler 24-Aug-12 17:15pm    
My 5
pasztorpisti 24-Aug-12 17:18pm    
Thank you!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900