在Linux套接字编程中接受后的错误

时间:2015-01-22 20:59:22

标签: c linux sockets error-handling

accept()部分的RETURN VALUE手册页中所述:

  

错误处理
  Linux accept()(和accept4())将新套接字上已有的网络错误作为accept()的错误代码传递。此行为与其他BSD套接字实现不同。为了可靠运行,应用程序应检测accept()之后为协议定义的网络错误,并通过重试将其视为EAGAIN。在TCP / IP的情况下,这些是ENETDOWNEPROTOENOPROTOOPTEHOSTDOWNENONETEHOSTUNREACH,{{1} }和EOPNOTSUPP

这是否意味着必须在ENETUNREACH返回之后和检查errno的返回值之前检查accept()的值?如果是,如果设置accept(),必须采取哪些步骤?

这是我处理errno的代码片段:

accept()

我的结论是,在这种情况下,人们可能会在一段时间内再试一次。我的结论是否正确?

3 个答案:

答案 0 :(得分:3)

根据SUSv4

  

成功完成后,accept()将返回已接受套接字的非负文件描述符。否则,将返回-1并设置errno以指示错误。

这意味着,如果errno返回accept(),您只需检查-1

您的代码可能看起来更像这样:

ret = accept(fd, &addr, sizeof (addr));
if (ret == -1) {
    switch (errno) {
    case EAGAIN:
    case EWOULDBLOCK:
        /* do something */
        break;
    case EBADF:
        /* do something different */
        break;
    default:
        /* do something even more different */
    }
}

(您如何处理每个错误情况取决于您的应用程序。)

此外,在检查errno的返回值后,务必立即检查accept() 。如果您先调用任何其他函数(即使是简单的fprintf()),也可能会因错误而覆盖errno

答案 1 :(得分:2)

首先,检查accept()返回值。如果accept()返回值小于0,则应检查errno。如果是ENETDOWNEPROTOENOPROTOOPTEHOSTDOWNENONETEHOSTUNREACHEOPNOTSUPP或{{1} },然后你可以再次致电ENETUNREACH。否则发生了一些不好的事情,你应该停止拨打accept()(你已经通过了不好的侦听套接字作为accept()的参数,例如)。

这就是我对代码的理解。

以下是如何进行错误处理:

accept()

答案 2 :(得分:0)

您还应该处理EHOSTUNREACH,该消息显示“软件导致连接中止”。

我像接受的答案一样处理了accept()的返回值,但是我的一台服务器由于EHOSTUNREACH而崩溃。 在google之后,我意识到ECONNABORTED错误发生后套接字凭据也没有更改。我们不应该只为ECONNABORTED而使程序崩溃。

其各种约束如下:

  1. 如果尚未建立连接,即这是来自客户端的第一个请求,并且即使在服务器没有机会响应之前客户端也关闭了连接,请在以下位置接受accept():服务器结果为ECONNABORTED。服务器应忽略此错误,并继续处理队列中的下一个请求。如果客户端需要再次连接到服务器,则必须执行另一个connect()。

  2. 如果客户端与服务器之间的连接处于ESTABLISHED状态,并且客户端突然关闭连接,则服务器上的accept()调用将生成ECONNABORTED。在这种情况下,服务器必须关闭半打开的连接。否则,只要服务器进程处于活动状态,那些半开的套接字就可以保持CLOSE_WAIT状态。请访问以下网页:http://technopark02.blogspot.com/200...closewait.html,以了解在稍有不同的情况下CLOSE_WAIT及其影响的更多信息。

最后,完整的代码如下:

while(running)
{
    sfd = accept(socketFd, (struct sockaddr *) &cli_addr, &addr_len);
    if( sfd < 0)
    {
        if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENONET ||
            errno == EPROTO || errno == ENOPROTOOPT || errno == EOPNOTSUPP ||
            errno == ENETDOWN || errno == ENETUNREACH || errno == EHOSTDOWN ||
            errno == EHOSTUNREACH || errno == ECONNABORTED)
        {
            log_warn("accept error: %s\n", strerror(errno));
            break;
        }
        else if( errno == EINTR)
        {
            continue;
        }
        else
        {
            log_error("AccepCb: accept error: %s\n", strerror(errno));
            assert(false);
        }
    }

    // logical works...
}