【问题标题】:How to keep a boost asio async read active continuously如何保持 boost asio 异步读取持续活跃
【发布时间】:2014-11-12 19:29:30
【问题描述】:

我正在构建一个 tcp 客户端,它必须发送请求和读取响应,但还必须能够检测来自 tcp 服务器的传入数据,这些数据不是对请求的响应 - 服务器可以发起一个 tx/rx 序列。

保持异步读取始终处于活动状态的最佳方法是什么。我尝试了以下方法:

在我的“handle_connect”方法中,我开始异步读取和异步写入。异步读取如下所示:

size_t bytes_transferred = BUFFER_SIZE; boost::asio::async_read(m_socket, boost::asio::buffer(rcvbuf, bytes_transferred), boost::bind(&CClientSock::handle_read, 这, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

异步写入填充缓冲区,然后开始写入:

boost::asio::async_write(m_socket, boost::asio::buffer(sndbuf, request_length), boost::bind(&CClientSock::handle_write, 这, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

在异步写入处理程序中 - 它什么也不做,因为异步读取已经开始。

这不起作用。应该从服务器对客户端写入的响应中读取的数据永远不会触发异步读取处理程序。我实际上不确定写入是否会执行...

由于读取和写入未按正常顺序排队,是否可以这样做?如果我需要开始写,我是否必须开始读取,然后取消它?

【问题讨论】:

  • 你能给我们展示更多相关的代码吗?目前还不清楚所有处理程序是如何实现的。

标签: c++ boost asynchronous


【解决方案1】:

嗯,我已经回答了我最初的问题,但是我提出了使用股线的可能性,所以我可能没有完全理解。

我最初的问题是重构代码的结果,没有意识到我之前的代码只在我测试的情况下才有效。我现在使用以下顺序进行此工作:

  • 发出 async_connect。
  • 在 connect_handler 问题中,async_read_some - 这最初是一个 async_read,由于可用字节数,它从未完成。这就是 Stack Overflow 问题的原因。
  • 在 connect_handler 中也发出一个 async_write。
  • 在 write_handler 中什么都不做,因为读取已经排队。
  • 写入触发服务器响应,read_handler 被正确调用。
  • read_handler 处理数据并将另一个 async_read_some 排队。

这个序列似乎可以无限重复而没有错误。

关于链 - 代码是多线程的,因此有多个线程,每个线程可能管理多个套接字连接。跨线程没有套接字调用 - 也就是说,除了在创建套接字的线程中之外,套接字永远不会被代码操作。但是项目只有一个 io_service 对象,这似乎是在多线程应用程序中使用 io_service 对象的推荐方式。

我是否正确,这里不需要股线?

【讨论】:

    【解决方案2】:

    在没有明确的 SSCCE/样本的情况下,我将强调一些想法:

    • 要接受“未经请求的”传入数据/请求,您通常使用侦听器来接受新的传入连接,而不是无限期地等待同一连接上的数据
    • 如果您需要在同一资源上对不同的异步任务进行排序,请使用 Boost Asio strand: Why do I need strand per connection when using boost::asio?
    • 要继续阅读,在基于 Actor 的异步中,只需从完成处理程序中发布前一个读取操作的读取操作:

       void handle_read(boost::system::error_code ec, size_t bytes_received) {
           if (!ec)
           {
      
               /* do your usual handling on the incoming data */
      
      
               boost::asio::async_read(m_socket,
                  boost::asio::buffer(rcvbuf, bytes_transferred),
                  boost::bind(&CClientSock::handle_read, 
                  this,
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred));
           }
      
       }
      

    【讨论】:

    • 有用的答案。我对您的代码示例有疑问:进行这种链接时是否存在堆栈溢出的风险?
    • @GabrielDevillers 没问题。启动异步任务不是递归:stackoverflow.com/a/43885439/85371
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    相关资源
    最近更新 更多