非阻塞TCP套接字在read()上连续接收EAGAIN

时间:2014-01-15 05:12:54

标签: sockets tcp nonblocking

TCP套接字已设置为非阻塞。

以下是代码:

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

以下是将GET请求发送到网页时的工作原理:

#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

read()应返回n = 0,以便在读取网页中的所有内容后停止while循环。但这不是。

更新: 当我在办公室测试此代码时,会出现上述故障情况。当我回到家时它起作用:

#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

我知道公司网络中的防火墙可能会禁用某些网络服务,例如ping,但为什么read()可以读取内容但无法停止?

1 个答案:

答案 0 :(得分:1)

  

read()应返回n = 0,以便在读取网页中的所有内容后停止while循环。

不,不应该。当对等体关闭连接时,它应该返回零。

您是HTTP keep-alive的受害者。如果您不想这样,请发送标题Connection: close。否则你需要读取所有标题,然后从Content-length标题中获取正文大小,并准确读取那么多字节。

请注意,以这种方式使用非阻塞套接字完全没有意义。你的睡眠时间太短或太长。阻塞模式recv()read()阻塞了恰当的时间长度,它是一行代码。如果您想要套接字超时,请设置SO_RCVTIMEO.