Skip to content

Boost.Asio — 异步 I/O

Boost.Asio 是 C++ 异步网络编程的事实标准,也是 C++ 网络 TS 的基础。支持 TCP/UDP/串口/定时器,配合协程极其强大。

安装

bash
# vcpkg(独立 asio,不依赖 Boost)
vcpkg install asio

# 或者完整 Boost
vcpkg install boost-asio

# CMake
find_package(Boost REQUIRED COMPONENTS system)
target_link_libraries(myapp PRIVATE Boost::system)
# 或独立 asio
find_package(asio REQUIRED)
target_link_libraries(myapp PRIVATE asio::asio)

核心概念

io_context  — 事件循环,驱动所有异步操作
executor    — 决定回调在哪里执行
strand      — 串行化执行,避免并发回调
socket      — TCP/UDP 套接字
acceptor    — TCP 服务端监听
resolver    — DNS 解析
timer       — 定时器
buffer      — 数据缓冲区

TCP 服务端

cpp
#include <boost/asio.hpp>
#include <iostream>
#include <memory>

namespace asio = boost::asio;
using tcp = asio::ip::tcp;

class Session : public std::enable_shared_from_this<Session> {
    tcp::socket socket_;
    std::array<char, 4096> buf_;

public:
    explicit 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(asio::buffer(buf_),
            [this, self](boost::system::error_code ec, size_t n) {
                if (!ec) {
                    do_write(n);
                }
            });
    }

    void do_write(size_t n) {
        auto self = shared_from_this();
        asio::async_write(socket_, asio::buffer(buf_, n),
            [this, self](boost::system::error_code ec, size_t) {
                if (!ec) {
                    do_read();  // 继续读
                }
            });
    }
};

class Server {
    tcp::acceptor acceptor_;

public:
    Server(asio::io_context& io, uint16_t port)
        : acceptor_(io, tcp::endpoint(tcp::v4(), port))
    {
        do_accept();
    }

private:
    void do_accept() {
        acceptor_.async_accept([this](boost::system::error_code ec, tcp::socket socket) {
            if (!ec) {
                std::make_shared<Session>(std::move(socket))->start();
            }
            do_accept();  // 继续接受连接
        });
    }
};

int main() {
    asio::io_context io;
    Server server(io, 8080);
    std::cout << "服务器启动,端口 8080\n";
    io.run();  // 事件循环
}

TCP 客户端

cpp
#include <boost/asio.hpp>

namespace asio = boost::asio;
using tcp = asio::ip::tcp;

int main() {
    asio::io_context io;
    tcp::resolver resolver(io);
    tcp::socket socket(io);

    // 同步连接
    auto endpoints = resolver.resolve("example.com", "80");
    asio::connect(socket, endpoints);

    // 发送 HTTP 请求
    std::string request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
    asio::write(socket, asio::buffer(request));

    // 读取响应
    boost::system::error_code ec;
    std::string response;
    asio::read_until(socket, asio::dynamic_buffer(response), "\r\n\r\n", ec);
    std::cout << response << "\n";
}

协程风格(C++20,推荐)

cpp
#include <boost/asio.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/detached.hpp>

namespace asio = boost::asio;
using tcp = asio::ip::tcp;

// 协程 echo 服务端
asio::awaitable<void> handle_client(tcp::socket socket) {
    try {
        std::array<char, 4096> buf;
        while (true) {
            size_t n = co_await socket.async_read_some(
                asio::buffer(buf), asio::use_awaitable);
            co_await asio::async_write(
                socket, asio::buffer(buf, n), asio::use_awaitable);
        }
    } catch (const std::exception& e) {
        // 连接断开
    }
}

asio::awaitable<void> listener(uint16_t port) {
    auto executor = co_await asio::this_coro::executor;
    tcp::acceptor acceptor(executor, {tcp::v4(), port});

    while (true) {
        tcp::socket socket = co_await acceptor.async_accept(asio::use_awaitable);
        asio::co_spawn(executor, handle_client(std::move(socket)), asio::detached);
    }
}

int main() {
    asio::io_context io;
    asio::co_spawn(io, listener(8080), asio::detached);
    io.run();
}

定时器

cpp
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>

namespace asio = boost::asio;

int main() {
    asio::io_context io;

    // 一次性定时器
    asio::steady_timer timer(io, std::chrono::seconds(3));
    timer.async_wait([](boost::system::error_code ec) {
        if (!ec) std::cout << "3秒后触发\n";
    });

    // 周期定时器(协程风格)
    asio::co_spawn(io, [&]() -> asio::awaitable<void> {
        asio::steady_timer t(co_await asio::this_coro::executor);
        while (true) {
            t.expires_after(std::chrono::seconds(1));
            co_await t.async_wait(asio::use_awaitable);
            std::cout << "每秒触发\n";
        }
    }, asio::detached);

    io.run();
}

多线程 io_context

cpp
#include <boost/asio.hpp>
#include <thread>
#include <vector>

namespace asio = boost::asio;

int main() {
    asio::io_context io;

    // 防止 io_context 在没有任务时退出
    auto work = asio::make_work_guard(io);

    // 多线程运行事件循环
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back([&io] { io.run(); });
    }

    // strand:确保回调串行执行(避免并发问题)
    asio::strand<asio::io_context::executor_type> strand(io.get_executor());

    asio::post(strand, [] { std::cout << "串行任务 1\n"; });
    asio::post(strand, [] { std::cout << "串行任务 2\n"; });
    // 两个任务不会并发执行

    work.reset();  // 允许 io_context 退出
    for (auto& t : threads) t.join();
}

关键认知

Boost.Asio 的核心是Proactor 模式:发起异步操作,操作完成时回调。协程风格(co_await)让异步代码的可读性接近同步代码,是现代 Asio 的推荐用法。多线程时用 strand 串行化回调,避免数据竞争。

系统学习 C++ 生态,深入底层架构