Question

The TCP socket has been set to nonblocking.

Here's the code:

char * recv_response(int sockfd)
{
    char * resp_msg = (char *)malloc(MAX_RESP_LEN);

    int n, len;
    len = 0;
    while (1) {
        n = read(sockfd, resp_msg + len, 1024);
        printf("#recv_response. n = %d, len = %d#\n", n, len);
        if (n < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                printf("#recv_response. errno = EAGAIN#\n");
                sleep(5);
                continue;
            }   
            else if (errno == EINTR) {
                printf("recv interruputed\n");
                close(sockfd);
                return NULL;
            }   
        }   
        else if (n == 0)  
            break;
        else
            len += n;
    }   
    close(sockfd);
    resp_msg = realloc(resp_msg, len + 1); 
    return resp_msg;    
}

And here's how it works when sending GET request to a webpage:

#recv_response. n = -1, len = 0#
#recv_response. errno = EAGAIN#
#recv_response. n = 1024, len = 0#
#recv_response. n = 1024, len = 1024#
#recv_response. n = 1024, len = 2048#
#recv_response. n = 1024, len = 3072#
#recv_response. n = 1024, len = 4096#
#recv_response. n = 909, len = 5120#
#recv_response. n = -1, len = 6029#
#recv_response. errno = EAGAIN#
#recv_response. n = -1, len = 6029#
#recv_response. errno = EAGAIN#
#recv_response. n = -1, len = 6029#
#recv_response. errno = EAGAIN#
#recv_response. n = -1, len = 6029#
#recv_response. errno = EAGAIN#
^C

The read() should return n=0 to stop the while loop after all stuff in the webpage is read. But here it's not.

UPDATE: The above failure case happens when I tested this code in office. When I came back to home it works:

#recv_response. n = -1, len = 0#
#recv_response. errno = EAGAIN#
#recv_response. n = 1024, len = 0#
#recv_response. n = 1024, len = 1024#
#recv_response. n = 1024, len = 2048#
#recv_response. n = 1024, len = 3072#
#recv_response. n = 1024, len = 4096#
#recv_response. n = 227, len = 5120#
#recv_response. n = 0, len = 5347#
HTTP/1.1 200 OK

I know that firewalls in company network may ban some network services like ping, but why here the read() can read stuff but can't stop?

Was it helpful?

Solution

The read() should return n=0 to stop the while loop after all stuff in the webpage is read.

No it shouldn't. It should return zero when the peer closes the connection.

You are a victim of HTTP keep-alive. If you don't want that, send the header Connection: close. Otherwise you need to read all the headers, then get the body size from the Content-length header, and read exactly that many bytes.

Note that using non-blocking sockets in this way is completely and utterly pointless. Your sleep is either too short or too long. A blocking-mode recv() or read() blocks for exactly the right length of time, and it's one line of code. If you want a socket timeout, set SO_RCVTIMEO.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top