正如其他人所提到的,您可以使用 select() 设置套接字变得可读的时间限制。
默认情况下,当套接字接收缓冲区中有一个或多个字节可用时,套接字将变为可读。我说“默认”是因为这个数量可以通过使用 SO_RCVLOWAT 套接字选项设置套接字接收缓冲区“低水位标记”来调整。
下面是一个函数,您可以使用它来确定套接字是否准备好在指定的时间限制内被读取。如果套接字有可读取的数据,它将返回 1。否则超时返回0。
代码基于 Unix Network Programming (www.unpbook.com) 一书中的示例,该示例可以为您提供更多信息。
/* Wait for "timeout" seconds for the socket to become readable */
readable_timeout(int sock, int timeout)
{
struct timeval tv;
fd_set rset;
int isready;
FD_ZERO(&rset);
FD_SET(sock, &rset);
tv.tv_sec = timeout;
tv.tv_usec = 0;
again:
isready = select(sock+1, &rset, NULL, NULL, &tv);
if (isready < 0) {
if (errno == EINTR) goto again;
perror("select"); _exit(1);
}
return isready;
}
像这样使用它:
if (readable_timeout(sock, 5/*timeout*/)) {
recv(sock, ...)
您提到在客户端处理 SIGPIPE,这是一个单独的问题。如果您得到这意味着您的客户端正在写入套接字,即使在收到来自服务器的 RST 之后也是如此。这是与对recv() 的阻塞调用问题不同的问题。
可能出现的情况是服务器崩溃并重新启动,失去其 TCP 状态。您的客户端将数据发送到服务器,该服务器发回 RST,因为它不再具有连接状态。您的客户端忽略 RST 并尝试发送更多数据,这是第二次 send() 导致您的程序接收 SIGPIPE 信号。
调用 recv() 时遇到了什么错误?