[英]Blocking recv call hangs if server is down
另一个套接字问题。
在我的客户端代码中,我正在发送一些数据包并期望从服务器端得到一些响应:
发送()
send()之后,服务器立即崩溃并重新启动。 同时,recv()正在等待。 但是即使服务器启动后,接收呼叫仍会挂起。 我添加了SIGPIPE信号处理,但是它仍然无法识别套接字已损坏。
当我取消操作时,我从recv()收到了已发出中断的错误消息。
有人可以帮助我如何纠正此错误?
它位于Solaris计算机上运行的共享库中。
可能是您应该设置超时延迟以管理这种情况。 通过使用setsockopt并在套接字上设置SO_RECVTIMEO标志,可以轻松完成此操作:
struct timeval tv;
tv.tv_sec = 30;
tv.tv_usec = 0;
if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
{
perror("setsockopt");
return -1;
}
另一种可能性是使用非阻塞套接字,并使用poll(2)或select(2)管理读/写内容。 您应该看一下Beej的《网络编程指南》 。
正如其他人提到的,您可以使用select()设置套接字可读的时间限制。
默认情况下,当套接字接收缓冲区中有一个或多个字节可用时,套接字将变得可读。 我说“默认”是因为通过使用SO_RCVLOWAT套接字选项将套接字接收缓冲区设置为“低水位标记”可以调整此数量。
您可以使用以下函数来确定套接字是否已准备好在指定的时限内读取。 如果套接字具有可读取的数据,它将返回1。 否则,超时将返回0。
该代码基于Unix网络编程(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()遇到什么错误?
问题是该连接从未真正关闭过。 (没有发送FIN包,等等,另一端就消失了。)
您要执行的操作是,使用带有SO_RCVTIMEO作为options_name的setsockopt(3) SO_RCVTIMEO
套接字上的超时设置。
在Solaris上使recv()调用nono-blockign的另一种方法是使用fcntl()将套接字描述符设置为非阻塞:
fcntl(sockDesc,F_SETFL,O_NONBLOCK);
这可以与select()一起使用,以保护recv()免受错误的select()返回值的影响(如果select()返回正且套接字上没有数据)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.