如果服务器关闭,阻止recv调用将挂起

Adi*_*dil 6 c sockets solaris

另一个插座问题.

在我的客户端代码中,我发送一些数据包并从服务器端发出一些响应:


发送()

recv()< - 它正在阻塞

在send()之后,服务器立即崩溃并重新启动.与此同时,recv()正在等待.但即使在服务器启动后,接收呼叫也会挂起.我已经添加了SIGPIPE信号处理,但它仍然无法识别套接字是否已损坏.

当我取消操作时,我从recv()得到了已发出中断的错误.

有人可以帮我解决这个错误吗?

这是在Solaris计算机上运行的共享库中.

Pat*_*ick 6

可能是您应该设置超时延迟以便管理此案例.它可以通过使用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;
  }
Run Code Online (Sandbox Code Playgroud)

另一种可能性是使用非阻塞套接字并使用poll(2)或select(2)管理读/写内容.你应该看看Beej的网络编程指南.

  • 另一个尝试的是SO_KEEPALIVE,如果这当然是TCP :) (2认同)

Tod*_*ton 4

正如其他人提到的,您可以使用 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;
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

if (readable_timeout(sock, 5/*timeout*/)) {
    recv(sock, ...)
Run Code Online (Sandbox Code Playgroud)

您提到在客户端处理 SIGPIPE 这是一个单独的问题。如果您收到此消息,则意味着您的客户端正在写入套接字,即使在从服务器接收到 RST 后也是如此。这是一个与阻塞调用 recv() 问题不同的问题。

可能出现的情况是服务器崩溃并重新启动,从而丢失其 TCP 状态。您的客户端将数据发送到服务器,服务器发回 RST,因为它不再具有连接状态。您的客户端忽略 RST 并尝试发送更多数据,正是第二个 send() 导致您的程序接收 SIGPIPE 信号。

调用 recv() 时出现什么错误?