Boost asio TCP asynchronous сервер не async?

Я использую код, приведенный в примере Boost .

Сервер принимает только одно соединение за раз. Это означает, что никаких новых соединений до тех пор, пока текущий не будет закрыт.

Как заставить вышеуказанный код одновременно принимать неограниченные соединения?

#include  #include  #include  #include  #include  using boost::asio::ip::tcp; class session : public std::enable_shared_from_this { 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(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 \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; } 

Как вы видите, программа ждет сна, и тем временем не получает второго соединения.

Вы выполняете синхронное ожидание внутри обработчика, который работает на единственном streamе, который обслуживает ваш io_service. Это заставляет Asio ждать с вызовом обработчиков для любых новых запросов.

  1. Используйте deadline_time с wait_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_ является timer_ boost::asio::deadline_timer session

  2. как решение для бедных людей добавляет больше streamов (это просто означает, что если при поступлении большего количества запросов в то же время есть streamи для их обработки, они все равно будут блокироваться до тех пор, пока первый stream не станет доступен для получения нового запроса)

     boost::thread_group tg; for (int i=0; i < 10; ++i) tg.create_thread([&]{ io_service.run(); }); tg.join_all(); 

И исходный код, и модифицированный код являются асинхронными и принимают несколько соединений. Как видно из следующего fragmentа, операция AcceptHandler async_accept инициирует другую операцию async_accept , формируя asynchronous цикл:

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

sleep() в ReadHandler session заставляет один stream, выполняющий io_service блокироваться до тех пор, пока сон не завершится. Следовательно, программа ничего не сделает. Однако это не приводит к отмене каких-либо выдающихся операций. Для лучшего понимания асинхронных операций и io_service рассмотрите этот ответ.


Ниже приведен пример, демонстрирующий сервер, обрабатывающий несколько соединений. Он генерирует stream, который создает 5 клиентских сокетов и подключает их к серверу.

 #include  #include  #include  #include  #include  #include  #include  using boost::asio::ip::tcp; class session : public std::enable_shared_from_this { 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(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 \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> clients; for (auto i = 0; i < 5; ++i) { auto client = std::make_shared( 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