tcp套接字读取调用如何永不返回

时间:2013-02-27 12:58:08

标签: c sockets tcp client-server buffer

客户报告了我无法理解的错误。基于TCP的客户端连接到从中接收数据的服务器,很少发送任何内容。通常一切都很好,但一旦在蓝色的月亮,就会发生这种情况:

  • 服务器发送一些数据
  • 客户端收到数据
  • 客户端正在处理数据
  • ...同时服务器发送更多数据
  • 客户端完成处理
  • 客户端尝试从套接字
  • 中读取数据
  • 客户端在处理
  • 后永远挂起第一个read()语句
  • 服务器关闭连接
  • 客户端仍然挂起

以下是如何建立tcp连接(剥离所有日志,返回检查等)

ret = inet_pton(AF_INET, conn->address, &addr.sin_addr);
addr.sin_port        = htons(conn->port); /* Server port */
addr.sin_family      = AF_INET;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (struct sockaddr *) &addr, sizeof(addr));

这是阅读包装器:

int32_t _readn ( int fd, uint8_t *vptr, int32_t n )
{
  int32_t  nleft;
  int32_t  nread;
  uint8_t*     ptr;

  ptr = vptr;
  nleft = n;
  while (nleft > 0) {
    if ((nread = read (fd, ptr, nleft)) < 0) {
      if (errno == EINTR) {
        nread = 0;
      } else {
        return E_NETWORK_ERROR;
      }
    } else if ( nread == 0 ) {
      break;
    }
    nleft -= nread;
    ptr   += nread;
  }
  return  (n-nleft);
}

即使在连接关闭后,是否可以永久阻止读取调用?

我的包装中是否存在某种棘手的错误,我没注意到这可能会导致这种情况?我应该在连接时为套接字设置一些标志吗?

2 个答案:

答案 0 :(得分:4)

问题的根源是如果没有数据要读取将阻止读取。例如。如果写入的字节少于预期的n个字节。这被称为阻塞读取。

要发现是否有数据,请使用select作为Jite说。

最后,您可能会有防火墙丢弃实时连接。一些防火墙被配置为切断已经打开超过给定时间的连接,例如, 30分钟。可能这不是你所拥有的。

答案 1 :(得分:2)

我最终使用基于选择的函数来检查数据是否可用。

虽然神秘数据丢失背后的原因仍然未知(没有服务器错误被证实),但这似乎可以解决问题:

int32_t isReadDataAvailableOnSocket ( int sock, uint32_t waitTimeUs )
{
  fd_set fds;
  int16_t ret = 0;
  struct timeval timeout;
  struct timeval* timeoutPtr = NULL;

  if (waitTimeUs>0) {
    timeout.tv_sec = waitTimeUs / 1000000;
    timeout.tv_usec = waitTimeUs % 1000000;
    timeoutPtr = &timeout;
  }

  FD_ZERO ( &fds );
  FD_SET ( sock, &fds );

  ret = select ( sock+1, &fds, NULL, NULL, timeoutPtr );
  if (ret == -1) {
    WARN("select failed for udp socket=[%d]", sock);
    return E_NETWORK_ERROR;
  }
  if ( ! FD_ISSET(sock, &fds) )
  {
    return E_NO_DATA;
  }
  else
  {
    return 0;
  }
}