boost :: asio :: async_read简单示例上的100%CPU使用率

时间:2013-12-18 02:59:24

标签: c++ sockets networking boost boost-asio

async_accept() socket对象移动到session对象(处理所有async_read()对象之后的boost :: asio standard examples中通过将其初始化为以下内容来调用:

std::make_shared<session>(std::move(socket_))->start();

当构建一个session它再次移动时(不是它可以减少吗?):

session(tcp::socket socket)
  : socket_(std::move(socket))

然后从客户端读取如下:

boost::asio::async_read(socket_, ...

一切顺利。但是当我试图使async_read()不是来自session对象而是直接来自async_accept()并使用它的socket对象时,CPU会在客户端连接后立即提高到100%。为什么呢?

#include <boost/asio.hpp>
using boost::asio::ip::tcp;

class Server
{
public:
  Server(boost::asio::io_service& io_service,
         const tcp::endpoint& endpoint)    
    : acceptor_(io_service, endpoint),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
       [this](boost::system::error_code ec)
       {
         if (!ec) {
           char* buf = new char[5];
           boost::asio::async_read(socket_,
              boost::asio::buffer(buf, 5),
              [this, buf](boost::system::error_code ec, std::size_t)
              {
                if (!ec) {
                  std::cout.write(buf, 5);
                  std::cout << std::endl;
                }
                delete[] buf;
              });
         }
         do_accept();
       });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
};

int main(int argc, char* argv[])
{
  int port = 22222;
  boost::asio::io_service io_service;
  tcp::endpoint endpoint(tcp::v4(), port);
  new Server(io_service, endpoint);
  io_service.run();
}

提升1.49

修改

感谢您的回答!我最后移动socket_才使用它:

tcp::socket *socket = new tcp::socket(std::move(socket_));

Repeated std::move on an boost::asio socket object in C++11

也讨论了同样的问题

2 个答案:

答案 0 :(得分:3)

如果传递给basic_socket_acceptor::async_accept() peer 套接字未打开,则它将在async_accept()操作期间打开。否则,如果 peer 已经打开,那么 handler 将被发布到io_service进行调用,错误代码为boost::asio::error::already_open。因此,发布的代码会导致紧密的异步调用链形成:

  1. 第一次调用async_accept()操作,导致socket_被打开。
  2. async_accept()处理程序调用{​​{1}},启动do_accept()操作。
  3. async_accept()已经打开,导致socket_操作将其处理程序发布到async_accept(),错误为io_service
  4. 异步调用链从第2步开始。
  5. 在官方示例中未观察到此行为,因为socket's move operator导致移动的对象处于与使用basic_stream_socket(io_service&)构造函数构造的状态相同的状态。因此,移动的对象处于关闭状态,并准备好接受。

答案 1 :(得分:1)

您在所有地方都使用单socket_,因此当接受连接时,您的处理程序再次调用do_accept()并使用相同的socket_,然后一次又一次地接受它。 ..

您可能需要始终使用如下所示的新套接字:

  void do_accept()
  {
    boost::shared_ptr<tcp::socket> psocket(new tcp::socket(io_service));
    acceptor_.async_accept(*psocket, boost::bind(&Server::handleAccept, this, psocket, _1));
  }

  void handleAccept(boost::shared_ptr<tcp::socket> psocket, const boost::system::error_code& ec)
  {
    if (!ec) {
    char* buf = new char[5];
    boost::asio::async_read(
      *psocket,
      boost::asio::buffer(buf, 5),
      [this, buf](boost::system::error_code ec, std::size_t)
      {
        if (!ec) {
          std::cout.write(buf, 5);
          std::cout << std::endl;
        }
        delete[] buf;
      });
    }
    do_accept();
  }