【问题标题】:Understandng the reason for recv blocking forever了解 recv 永远阻塞的原因
【发布时间】:2016-04-02 10:08:48
【问题描述】:

我运行一个用 C 编写的 Linux 程序,它会通过解析 HTTP 响应定期接收数据,处理一些数字,然后通过另一个网页的 HTTP GET 报告结果。

我的问题是,有时其中一个实例会“冻结”。

查看top 我可以看到它处于sk_wait_data 状态并附加一个调试器显示它被recv 调用阻止。

这是进行 TCP 连接的代码的最小版本(改编自 http://www.linuxhowtos.org/C_C++/socket.htm):

int connectTCP(const char* host, const char* page, int portno) {
    int sockfd;

    struct sockaddr_in serv_addr;
    struct hostent *server;

    // Create socket //
    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd < 0) 
        error("ERROR opening socket");


    // Get ip from hostname //
    server = gethostbyname(host);
    if (server == NULL)
        error("ERROR, can not find host\n");

    memset((char *) &serv_addr, 0, sizeof(serv_addr));


    serv_addr.sin_family = AF_INET;
    memcpy((char *)&serv_addr.sin_addr.s_addr,   // Destination
            (char *)server->h_addr,  // Source
            server->h_length);       // Size
    serv_addr.sin_port = htons(portno);

    // Conect to socket //
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
        error("ERROR connecting");

    return sockfd;

}

char* httpGet(const char* host, const char* page, int portno) {
  int sockfd, n;

  sockfd = connectTCP(host, page, portno);
  memset(buffer, 0, sizeof(buffer));

  sprintf(buffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", page, host);

  n = send(sockfd,buffer,strlen(buffer), 0);

  if (n < 0) 
    error("ERROR writing to socket");

  int count = 0;
  do {
    n = recv(sockfd, buffer + count, BUFFER_MAX_SIZE - count, 0);
    if (n < 0) {
      error("ERROR reading from socket");

    }

    count += n;
  } while(n != 0);

  close(sockfd);

  return buffer;
}

【问题讨论】:

  • 如果页面大于缓冲区会怎样?
  • 如果第一个 recv() 返回的字节数少于仍在缓冲区中的 GET 发送字符串会怎样?
  • 您需要进行更多调试,或展示您的 html 解析和缓冲区管理如何工作,或两者兼而有之。
  • 另外,链接中的示例代码很糟糕。从头开始,它有令人讨厌的货物崇拜'bzero(buffer,256);'在其中,可能还有更多问题。您应该知道网络上有许多蹩脚、糟糕、糟糕和/或完全错误的服务器客户端示例:(
  • 尽管每个人都说如果有可用数据,recv 会立即返回,但我可以在 Linux 上完全重现此问题。即使对方的发送返回,recv 也会阻塞。

标签: linux sockets networking tcp


【解决方案1】:

代码中的错误:

  1. 如果recv() 返回零,您应该关闭套接字并停止读取。

  2. 如果 recv() 返回 -1,您应该报告错误,关闭套接字并停止读取,除非您设置了读取超时并且 errno 是 EAGAIN/EWOULDBLOCK,在这种情况下您应该处理但是超时适用于您的应用程序。

【讨论】:

  • 为什么 #1 是错误?我在想如果recv返回0,就没有更多的数据要读取,我可以关闭socker并返回缓冲区。关于#2,我确实在错误函数中报告了错误并退出程序。我不确定我是否理解你写的关于 EAGAIN/EWOULDBLOCK...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
相关资源
最近更新 更多