sockets - 接受套接字可以具有值得重试的暂时性故障吗?

标签 sockets boost-asio

这个问题主要是针对boost::asio的,但是socket标记上的问题可能会深入了解有关accept调用的瞬时失败。

在Boost::Asio中,如果我有一个套接字接受器编码为持续接受新连接。

void Acceptor::StartNextAccept()
{
    // _acceptor is of type boost::asio::ip::tcp::acceptor

    _acceptor->async_accept([this](const boost::system::error_code& ec, boost::asio::ip::tcp::socket sock) {
        if (ec)
        {
            // error
            LogErrorCode(ec);
        }
        else
        {
            // success
            HandleNewConnection(s);
        }

        StartNextAccept(); // enqueue another accept call regardless of success or error case

    });
}

我担心的是,如果接受套接字进入错误状态,那么上面的代码将处于无限循环中,不断记录故障,并无限期地进行新的尝试。因此,烧毁内核并不必要地填充日志文件。

更好的假设是:
  • async_accept调用应该永远不会在有效套接字上失败。不必担心上面的代码,因为您已经认真检查了初始化套接字的错误并测试了代码。
  • async_accept调用可能会失败,但是重试它们绝没有任何意义,因此只需关闭此套接字并退出重试循环即可。
  • async_accept调用可能会出现短暂故障。检查错误
    代码以确定是否值得重试。

  • 如果上面的#3是正确的假设,建议检查哪些错误代码?而且,如果错误是暂时的(例如机器资源不足,句柄不足等),那么在重试之前等待几秒钟是否有意义,这样线程就不会烧掉内核了?

    更新:物有所值。我的主要平台是Mac和Windows 10。

    最佳答案

    网络层是否可以存在值得重试的暂时性问题?是的。

    但是,linux accept错误是从挂起的连接列表(积压)返回的,而例如BSD直接报告它们。

      Error handling
           Linux accept() (and accept4()) passes already-pending network errors
           on the new socket as an error code from accept().  This behavior
           differs from other BSD socket implementations.  For reliable
           operation the application should detect the network errors defined
           for the protocol after accept() and treat them like EAGAIN by
           retrying.  In the case of TCP/IP, these are ENETDOWN, EPROTO,
           ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, and
           ENETUNREACH.
    


    其他不适用于Asio的async_connect的条件例如EWOULDBLOCK/EAGAINEFAULT

    See boost::asio::error for the corresponding error_code names: https://www.boost.org/doc/libs/master/boost/asio/error.hpp



    否则,请遍历系统错误documented列表,然后查看您认为值得明确处理的错误。

    在我的代码中,我通常只是终止链:
    _acceptor->async_accept([this](const boost::system::error_code& ec, boost::asio::ip::tcp::socket sock) {
        if (ec) {
            LogErrorCode(ec);
        } else {
            HandleNewConnection(s);
            StartNextAccept();
        }
    });
    

    我的服务器将向其重新初始化监听器(在Asio中使用acceptor讲话)。当然,这本身可能会失败,服务器可能会关闭。

    您可能有也可能没有QoS要求,这些要求会提示您以不同的方式处理各个条件。

    最终,重新初始化受体可能会更健壮,例如网络配置何时更改?

    关于sockets - 接受套接字可以具有值得重试的暂时性故障吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61760828/

    相关文章:

    error-handling - 如何映射Windows系统错误代码以增强::error_condition?

    c++ - 异步写入套接字和用户值(boost::asio 问题)

    c++ - 虚拟 ASIO 服务回调?

    Java 套接字 : My server input stream will not read from the client output stream?

    c - 服务器客户端消息验证

    sockets - Haskell tcp 服务器,fd 错误太大

    c - 处理/定义 poll 系统调用的 struct pollfd 数组的有效方法

    sockets - Haskell 中的原始套接字

    c++ - boost asio unix 套接字重用

    c++ - boost::asio 多线程异步接受阻塞读/写服务器