提升asio TCP异步服务器不是异步?

时间:2014-10-26 16:36:01

标签: c++ c++11 boost asynchronous

我正在使用Boost example中提供的代码。

服务器一次只接受1个连接。这意味着,在当前关闭之前不会有新的连接。

如何使上述代码同时接受无限连接?

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class session
  : public std::enable_shared_from_this<session>
{
public:
  session(tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

  void start()
  {
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            boost::this_thread::sleep(boost::posix_time::milliseconds(10000));//sleep some time
            do_write(length);
          }
        });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  enum { max_length = 1024 };
  char data_[max_length];
};

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
        [this](boost::system::error_code ec)
        {
          if (!ec)
          {
            std::make_shared<session>(std::move(socket_))->start();
          }

          do_accept();
        });
  }

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

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: async_tcp_echo_server <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    server s(io_service, std::atoi(argv[1]));

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

如您所见,该程序等待睡眠,同时它也没有抓住第二个连接。

2 个答案:

答案 0 :(得分:2)

原始代码和修改后的代码都是异步的,并且接受多个连接。从以下代码段中可以看出,async_accept操作的AcceptHandler启动另一个async_accept操作,形成异步循环:

        .-----------------------------------.
        V                                   |
void server::do_accept()                    |
{                                           |
  acceptor_.async_accept(...,               |
      [this](boost::system::error_code ec)  |
      {                                     |
        // ...                              |
        do_accept();  ----------------------'
      });
}

sleep()的ReadHandler中的session导致运行io_service的一个线程阻塞,直到睡眠完成。因此,该计划将无所作为。但是,这不会导致任何未完成的操作被取消。为了更好地理解异步操作和io_service,请考虑阅读this answer。


以下是处理多个连接的服务器的示例demonstrating。它产生一个线程,创建5个客户端套接字并将它们连接到服务器。

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;

class session
  : public std::enable_shared_from_this<session>
{
public:
  session(tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

  ~session()
  {
    std::cout << "session ended" << std::endl;
  }

  void start()
  {
    std::cout << "session started" << std::endl;
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            do_write(length);
          }
        });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  enum { max_length = 1024 };
  char data_[max_length];
};

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
        [this](boost::system::error_code ec)
        {
          if (!ec)
          {
            std::make_shared<session>(std::move(socket_))->start();
          }

          do_accept();
        });
  }

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

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: async_tcp_echo_server <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    auto port = std::atoi(argv[1]);
    server s(io_service, port);

    boost::thread client_main(
        [&io_service, port]
        {
          tcp::endpoint server_endpoint(
              boost::asio::ip::address_v4::loopback(), port);

          // Create and connect 5 clients to the server.
          std::vector<std::shared_ptr<tcp::socket>> clients;
          for (auto i = 0; i < 5; ++i)
          {
              auto client = std::make_shared<tcp::socket>(
                  std::ref(io_service));
              client->connect(server_endpoint);
              clients.push_back(client);
          }

          // Wait 2 seconds before destroying all clients.
          boost::this_thread::sleep(boost::posix_time::seconds(2));
        });

   io_service.run();
   client_main.join();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

输出:

session started
session started
session started
session started
session started
session ended
session ended
session ended
session ended
session ended

答案 1 :(得分:1)

您正在处理程序内执行同步等待,该处理程序在为您的io_service提供服务的唯一线程上运行。这使得Asio等待调用任何新请求的处理程序。

  1. deadline_timewait_async

    一起使用
    void do_read() {
        auto self(shared_from_this());
        socket_.async_read_some(boost::asio::buffer(data_, max_length),
                                [this, self](boost::system::error_code ec, std::size_t length) {
            if (!ec) {
                timer_.expires_from_now(boost::posix_time::seconds(1));
                timer_.async_wait([this, self, length](boost::system::error_code ec) {
                        if (!ec)
                            do_write(length);
                    });
            }
        });
    }
    

    timer_字段是boost::asio::deadline_timer的{​​{1}}成员

  2. 作为穷人的解决方案添加更多线程(这只是意味着如果有更多请求同时到达而不是有线程来处理它们,它仍会阻塞,直到第一个线程可用于拾取新请求)

    session
相关问题