• 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

  • 相关阅读:
    GMC Graph-Based Multi-View Clustering
    python工具方法37 voc数据统计分析(box聚类、box散点图、类别频率统计、box面积统计)
    汉诺塔的2个非递归解法
    Java并发编程指南:如何正确使用信号量和线程池熔断机制
    STM32F103配置时钟源为内部HSI 主频为64mhz
    line-height用了这么久,你真的了解他么
    2022年全国职业院校技能大赛:网络系统管理项目-模块B--Windows样题2
    [Linux入门]---进程状态
    请解释一下React中的条件渲染(conditional rendering)。
    elment UI el-date-picker 月份组件选定后提交后台页面显示正常,提交后台字段变成时区格式
  • 原文地址:https://blog.csdn.net/liulilittle/article/details/126773845