Boost asio tcp async server not async?

I am using the code provided in the Boost example .

The server accepts only one connection at a time. This means no new connections until the current one is closed.

How to make the above code while using an unlimited number of connections?

#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; } 

As you can see, the program is waiting for sleep, and in the meantime it does not capture the second connection.

+3
c ++ boost asynchronous c ++ 11
source share
2 answers

You perform synchronous wait inside a handler that runs in only one thread serving your io_service. This keeps Asio waiting to call handlers for any new requests.

  • Use deadline_time with wait_async or,

     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); }); } }); } 

    Where the timer_ field is a member of boost::asio::deadline_timer session

  • since the solution for poor people adds more threads (this simply means that if more requests arrive at the same time than there are threads to process them, they will still be blocked until the first thread becomes available to receive a new request)

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

Both the source code and the modified code are asynchronous and accept multiple connections. As you can see from the following snippet, the async_accept AcceptHandler operation initiates another async_accept operation, forming an asynchronous loop:

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

sleep() in a session ReadHandler causes a single thread on which io_service is io_service to block until sleep completes. Therefore, the program will do nothing. However, this does not result in the cancellation of any outstanding transactions. For a better understanding of asynchronous operations and io_service consider the answer question this .


Here is an example of a server that handles multiple connections. It generates a stream that creates 5 client sockets and connects them to the server.

 #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; } 

Exit:

 session started session started session started session started session started session ended session ended session ended session ended session ended 
+2
source share

All Articles