这个问题主要是针对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
});
}
我担心的是,如果接受套接字进入错误状态,那么上面的代码将处于无限循环中,不断记录故障,并无限期地进行新的尝试。因此,烧毁内核并不必要地填充日志文件。
更好的假设是:
代码以确定是否值得重试。
如果上面的#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
/EAGAIN
,EFAULT
。See
boost::asio::error
for the correspondingerror_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/