boost::corosio::tcp_server

TCP server with pooled workers.

Synopsis

class tcp_server;

Description

This class manages a pool of reusable worker objects that handle incoming connections. When a connection arrives, an idle worker is dispatched to handle it. After the connection completes, the worker returns to the pool for reuse, avoiding allocation overhead per connection.

Workers are set via set_workers as a forward range of pointer‐like objects (e.g., unique_ptr<worker_base>). The server takes ownership of the container via type erasure.

Thread Safety

Distinct objects: Safe. Shared objects: Unsafe.

Lifecycle

The server operates in three states:

Stopped: Initial state, or after join completes. ‐ Running: After start, actively accepting connections. ‐ Stopping: After stop, draining active work.

State transitions:

[Stopped] --start()--> [Running] --stop()--> [Stopping] --join()--> [Stopped]

Running the Server

io_context ioc;
tcp_server srv(ioc, ioc.get_executor());
srv.set_workers(make_workers(ioc, 100));
srv.bind(endpoint{address_v4::any(), 8080});
srv.start();
ioc.run();  // Blocks until all work completes

Graceful Shutdown

To shut down gracefully, call stop then drain the io_context:

// From a signal handler or timer callback:
srv.stop();

// ioc.run() returns after pending work drains.
// Then from the thread that called ioc.run():
srv.join();  // Wait for accept loops to finish

Restart After Stop

The server can be restarted after a complete shutdown cycle. You must drain the io_context and call join before restarting:

srv.start();
ioc.run_for( 10s );   // Run for a while
srv.stop();           // Signal shutdown
ioc.run();            // REQUIRED: drain pending completions
srv.join();           // REQUIRED: wait for accept loops

// Now safe to restart
srv.start();
ioc.run();

WARNING: What NOT to Do

‐ Do NOT call join from inside a worker coroutine (deadlock). ‐ Do NOT call join from a thread running ioc.run() (deadlock). ‐ Do NOT call start without completing join after stop. ‐ Do NOT call ioc.stop() for graceful shutdown; use stop instead.

Example

class my_worker : public tcp_server::worker_base
{
    corosio::tcp_socket sock_;
    capy::any_executor ex_;
public:
    my_worker(io_context& ctx)
        : sock_(ctx)
        , ex_(ctx.get_executor())
    {
    }

    corosio::tcp_socket& socket() override { return sock_; }

    void run(launcher launch) override
    {
        launch(ex_, [](corosio::tcp_socket* sock) -> capy::task<>
        {
            // handle connection using sock
            co_return;
        }(&sock_));
    }
};

auto make_workers(io_context& ctx, int n)
{
    std::vector<std::unique_ptr<tcp_server::worker_base>> v;
    v.reserve(n);
    for(int i = 0; i < n; ++i)
        v.push_back(std::make_unique<my_worker>(ctx));
    return v;
}

io_context ioc;
tcp_server srv(ioc, ioc.get_executor());
srv.set_workers(make_workers(ioc, 100));

Types

Name

Description

launcher

Move‐only handle to launch a worker coroutine.

worker_base

Abstract base class for connection handlers.

Member Functions

Name

Description

tcp_server [constructor] [deleted]

Construct a TCP server.

~tcp_server [destructor]

Destructor

operator= [deleted]

Assignment operators

bind

Bind to a local endpoint.

join

Block until all accept loops complete.

set_workers

Set the worker pool.

start

Start accepting connections.

stop

Stop accepting connections.

See Also

worker_base, set_workers, launcher

Created with MrDocs