accept插座会不会出现瞬时故障,值得重试?

问题描述 投票:1回答:1

这个问题主要是针对 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

    });
}

我担心的是,如果接受者socket进入错误状态,上面的代码将处于无限循环中,不断记录失败,enqueuing一个新的尝试,无止境。这样一来,就会烧掉一个核心,无谓地填满日志文件。

哪种假设更好。

  1. async_accept调用永远不会在有效的套接字上失败。不要担心上面的代码,因为你勤奋地检查了初始化套接字的错误并测试了你的代码。

  2. async_accept调用可能会失败,但重试它们永远没有意义,所以只需关闭这个套接字并退出重试循环。

  3. async_accept调用可能会有短暂的失败。 检查错误代码以确定是否值得重试。

如果上面的#3是正确的假设,那么建议检查的错误代码是什么? 而如果错误是瞬时的(比如机器资源低,句柄用完了等等......),等待几秒钟再重试,这样线程就不会烧核了吗?

更新: 就其价值而言,我的主要平台是Mac和Windows 10。我的主要平台是Mac和Windows 10。

sockets boost-asio
1个回答
1
投票

网络层会有值得重试的瞬时问题吗?是的,网络层会有短暂的问题。

然而,linux accept 错误会从挂起的连接列表(backlog)中返回,而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 例如 EWOULDBLOCKEAGAIN, EFAULT.

boost::asio::error 对应的 error_code 名称。https:/www.boost.orgdoclibsmasterboostasioerror.hpp

否则请查看系统错误列表 有据可查 并看看哪些你认为值得明确处理。

在我的代码中,我通常只是结束这个链。

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

我的服务器就会重新初始化监听器(acceptor 用Asio的话说)。) 当然,这本身可能会失败,对此服务器可能会关闭。

你可能有也可能没有QoS要求,促使你以不同的方式处理个别情况。

最终,重新初始化接受器可能会更稳健,例如,当网络配置发生变化时?

© www.soinside.com 2019 - 2024. All rights reserved.