• boost::asio::ip::tcp::acceptor::async_accept 一直被死循环调用(无错误)问题的处理。


    演示会发生异步死循环故障的代码实现:

    1. bool Socket::AcceptLoopbackAsync(
    2. const Hosting& hosting,
    3. const boost::asio::ip::tcp::acceptor& acceptor,
    4. const BOOST_ASIO_MOVE_ARG(AcceptLoopbackCallback) callback) noexcept {
    5. if (!acceptor.is_open()) {
    6. return false;
    7. }
    8. if (!hosting || !callback) {
    9. Closesocket(acceptor);
    10. return false;
    11. }
    12. const AsioContext context_ = hosting->GetContext();
    13. if (!context_) {
    14. Closesocket(acceptor);
    15. return false;
    16. }
    17. boost::asio::ip::tcp::acceptor* const acceptor_ = addressof(acceptor);
    18. const Hosting hosting_ = hosting;
    19. const AcceptLoopbackCallback accept_ = BOOST_ASIO_MOVE_CAST(AcceptLoopbackCallback)(constantof(callback));
    20. const AsioTcpSocket socket_ = make_shared_object(*context_);
    21. acceptor_->async_accept(*socket_,
    22. [hosting_, context_, acceptor_, accept_, socket_](const boost::system::error_code& ec) noexcept {
    23. if (ec == boost::system::errc::operation_canceled) {
    24. Closesocket(*acceptor_);
    25. return;
    26. }
    27. bool success = false;
    28. do { /* boost::system::errc::connection_aborted */
    29. if (ec) { /* ECONNABORTED */
    30. break;
    31. }
    32. int handle_ = socket_->native_handle();
    33. Socket::AdjustDefaultSocketOptional(handle_, false);
    34. Socket::SetTypeOfService(handle_);
    35. Socket::SetSignalPipeline(handle_, false);
    36. Socket::SetDontFragment(handle_, false);
    37. Socket::ReuseSocketAddress(handle_, true);
    38. /* Accept Socket?? */
    39. success = accept_(context_, socket_);
    40. } while (0);
    41. if (!success) {
    42. Closesocket(socket_);
    43. }
    44. success = AcceptLoopbackAsync(hosting_, *acceptor_, forward0f(accept_));
    45. if (!success) {
    46. Closesocket(*acceptor_);
    47. }
    48. });
    49. return true;
    50. }

    该问题发生的原因:

    进程的最大文件描述符太小,当进程打开的文件描述符句柄(fd)数量超过,当前进程的 “Max open files”,那么会导致 accept 无法获取 session fd 而失败,但它并不产生错误,而此时 TCP/IP 连接的三次握手(或 FAST OPEN,单次)已建立连接。

    boost::asio 采用 epoll LT(水平出发模式),该模式会导致,epoll 不停的触发 accept 事件到达,所以就产生了无限制的 async_accept 回调调用,故而又重新 async_accept,造成的死循环,即使没有实际的网络IO产生。

    查看特定进程的 “Max open files” 值大小,人们可以使用以下的命令

    cat /proc/进程PID/limits                        ## 打印内容如下

    Limit                     Soft Limit           Hard Limit           Units     
    Max cpu time              unlimited            unlimited            seconds   
    Max file size             unlimited            unlimited            bytes     
    Max data size             unlimited            unlimited            bytes     
    Max stack size            8388608              unlimited            bytes     
    Max core file size        0                    unlimited            bytes     
    Max resident set          unlimited            unlimited            bytes     
    Max processes             1178                 1178                 processes 
    Max open files            1000000              1000000              files     
    Max locked memory         67108864             67108864             bytes     
    Max address space         unlimited            unlimited            bytes     
    Max file locks            unlimited            unlimited            locks     
    Max pending signals       1178                 1178                 signals   
    Max msgqueue size         819200               819200               bytes     
    Max nice priority         0                    0                    
    Max realtime priority     0                    0                    
    Max realtime timeout      unlimited            unlimited            us

    通过命令设置当前终端会话,最大文件描述符数量:

    ulimit -n 1000000               ## 默认数量:1024

    确定某个进程打开的文件描述符数量

    lsof -Pnl +M -p 进程ID | wc -l 

    确定某个进程打开的文件描述符详细信息

    lsof -Pnl +M -p 进程ID

  • 相关阅读:
    docker
    SSH工具:XShell 常见的快捷命令整理汇总
    从零开始,开发一个 Web Office 套件(11):支持中文输入法(or 其它使用输入法的语言)
    Python函数(一)※
    Spring MVC中@InitBinder注解是如何应用的?
    天翎知识管理系统有哪些优势?
    Linux友人帐之Vim编译器
    SpringBoot集成rabbitMq
    容器相关的概念
    java毕业生设计新冠疫苗预约系统计算机源码+系统+mysql+调试部署+lw
  • 原文地址:https://blog.csdn.net/liulilittle/article/details/126773845