2014-01-15 115 views
0

TCP套接字已被设置为非阻塞。非阻塞TCP套接字在读取时持续接收EAGAIN()

下面的代码:

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()可以读的东西,但不能停下来?

+0

HTTP套接字是否保持活动状态?您应该在阅读内容长度标题时解析它,并使用它来知道该页面何时完成。 –

+0

谢谢。是的,我之前没有设置“Connection:close”。但有一点我仍不清楚为什么测试成功,当我在家里运行,与输入相同的URL。 – Lee

回答

1

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

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

你是HTTP保持活跃的受害者。如果您不想要,请发送标头Connection: close。否则,您需要读取所有标题,然后从Content-length标题获取正文大小,并精确读取多个字节。

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

+0

感谢您的建议。你是对的,保持联系是为什么阅读永不停止。关于阻塞和非阻塞,如果我想稍后支持多线程和epoll,应该在这里更好的选择nonblocking吗? – Lee

+0

你通常选择*多线程和非阻塞/ epoll之间的*。你通常不会全部使用它们。 – EJP