Quick Start
This guide walks you through building your first network application with Corosio: a simple echo server that accepts connections and echoes back whatever clients send.
| Code snippets assume: |
#include <boost/corosio.hpp>
#include <boost/corosio/acceptor.hpp>
#include <boost/capy/task.hpp>
#include <boost/capy/ex/run_async.hpp>
#include <boost/capy/buffers.hpp>
namespace corosio = boost::corosio;
namespace capy = boost::capy;
Step 1: Create the I/O Context
Every Corosio program starts with an io_context. This is the event loop that
processes all asynchronous operations:
int main()
{
corosio::io_context ioc;
// ... launch coroutines ...
ioc.run(); // Process events until all work completes
}
The run() method blocks and processes events until there’s no more work.
Step 2: Create an Acceptor
The acceptor listens for incoming TCP connections:
corosio::acceptor acc(ioc);
acc.listen(corosio::endpoint(8080)); // Listen on port 8080
The endpoint(port) constructor binds to all network interfaces on the
specified port.
Step 3: Write the Echo Session
Each client connection is handled by a coroutine that reads data and echoes it back:
capy::task<void> run_session(corosio::socket sock)
{
char buf[1024];
for (;;)
{
// Read some data
auto [ec, n] = co_await sock.read_some(
capy::mutable_buffer(buf, sizeof(buf)));
if (ec || n == 0)
break; // Connection closed or error
// Echo it back
auto [wec, wn] = co_await corosio::write(
sock, capy::const_buffer(buf, n));
if (wec)
break; // Write error
}
sock.close();
}
Key points:
-
read_some()returns when any data is available -
write()(the free function) writes all data or fails -
Structured bindings extract the error code and byte count
Step 4: Write the Accept Loop
The accept loop waits for connections and spawns sessions:
capy::task<void> accept_loop(
corosio::io_context& ioc,
corosio::acceptor& acc)
{
for (;;)
{
corosio::socket peer(ioc);
auto [ec] = co_await acc.accept(peer);
if (ec)
{
std::cerr << "Accept error: " << ec.message() << "\n";
break;
}
// Spawn the session coroutine
capy::run_async(ioc.get_executor())(run_session(std::move(peer)));
}
}
The run_async function launches a coroutine with executor affinity. Each
spawned session runs concurrently with the accept loop.
Step 5: Put It Together
int main()
{
corosio::io_context ioc;
corosio::acceptor acc(ioc);
acc.listen(corosio::endpoint(8080));
std::cout << "Echo server listening on port 8080\n";
capy::run_async(ioc.get_executor())(accept_loop(ioc, acc));
ioc.run();
}
Testing the Server
Start the server, then use netcat or telnet to test:
$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Hello, World!
Hello, World!
Error Handling Patterns
Next Steps
Now that you have a working echo server:
-
TCP/IP Networking — Networking fundamentals
-
Concurrent Programming — Coroutines and strands
-
HTTP Client Tutorial — Make HTTP requests
-
I/O Context Guide — Understand the event loop
-
Sockets Guide — Deep dive into socket operations