boost · advanced
Boost.Asio: An Async TCP Echo Server
An asynchronous TCP echo server ties the previous lessons together. An acceptor listens on the port and async_accept hands back a fresh socket per client; inside its handler you start a session for that client and immediately call async_accept again, so a single thread accepts an endless stream of connections without ever blocking. Each session then runs a self-sustaining chain: async_read_some fills a buffer, its completion handler async_writes those exact bytes back to echo them, and the write handler calls do_read() again — read, write, read — until an error occurs, which is the proactor's async state machine made concrete. The subtle part is object lifetime: because handlers execute later, the session must outlive every pending operation, so it derives from enable_shared_from_this and each handler captures self = shared_from_this(), keeping the session alive until its final async op completes; when an error_code such as end-of-file arrives (the client closed), the chain stops, the last shared_ptr drops, and the session is destroyed. With this pattern one thread comfortably serves thousands of concurrent connections.
Async echo server: async_accept starts a session per client and immediately re-arms to accept the next. Each session runs a read→echo-write→read chain (the async state machine). Use enable_shared_from_this and capture self in every handler so the session outlives its pending async ops; an EOF error_code ends the chain and frees it.
The code
void do_accept() { acceptor_.async_accept([this](auto ec, tcp::socket sock){ if (!ec) std::make_shared<session>(std::move(sock))->start(); do_accept(); // immediately accept the next client });}// session: enable_shared_from_this keeps it alive across async opsvoid session::do_read() { auto self = shared_from_this(); sock_.async_read_some(buffer(buf_), [this,self](auto ec, auto n){ if (!ec) async_write(sock_, buffer(buf_,n), [this,self](auto ec2, auto){ if(!ec2) do_read(); }); });}What this lesson walks through
- 01A non-blocking accept loop
- 02The read/write echo chain
- 03Lifetime: shared_from_this
The acceptor listens on the port. async_accept hands you a fresh socket for each client; inside its handler you start a session for that client AND immediately call async_accept again to wait for the next one. One thread thus accepts an endless stream of connections without ever blocking.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Boost.Asio: An Async TCP Echo Server and 100+ animated C++ interview lessons.