Boost.Asio C++ 网络/异步编程面试考点

Boost.Asio 是 C++ 网络/异步编程的经典库(现在也是 C++26 标准网络库 std::net 的蓝本),确实是后台开发、C++ 中间件岗位面试的高频考点。下面按"核心概念→常考问题→常见坑"整理一下。

一、核心概念(必须吃透)

1. io_context(事件循环核心)

  • 本质是一个任务调度器/事件分发器,负责执行所有异步操作的完成回调
  • run() / run_one() / poll() / poll_one() 的区别:run() 阻塞直到没有任务;poll() 不阻塞,只处理当前就绪的任务
  • 没有任务时 run() 会立即返回------这也是为什么常需要 executor_work_guard(或旧版 io_context::work)来"占住"事件循环,防止提前退出

2. Proactor 模式(Asio 的设计核心)

  • 区别于 Reactor 模式:Reactor 是"事件就绪后你自己去读/写",Proactor 是"你发起异步操作,操作完成后系统通知你结果"
  • 在 Windows 上 Asio 直接用 IOCP 实现真正的 Proactor;在 Linux 上底层是 epoll(Reactor),但 Asio 在上层模拟出 Proactor 语义------这个"模拟"过程是常问的深挖点

3. 异步操作模型

  • async_read / async_write / async_connect / async_accept 等,配合 completion handler(回调)
  • Handler 的签名、错误码 error_code 的传递方式(Asio 倾向用 error_code 而非异常)

4. Strand

  • 用于保证一组 handler 不会并发执行(即便你用多线程 io_context::run()),从而避免手动加锁
  • 常考:"多线程跑 io_context::run() 时如何保证共享资源安全" → 答案就是 strand

5. Buffer 管理

  • mutable_buffer / const_buffer / streambuf,以及为什么异步操作时 buffer 的生命周期必须由调用者保证(这是最容易挖的坑)

6. 协程支持

  • 早期的 stackful 协程(asio::spawn
  • C++20 co_await + asio::awaitable,这是现在业界更常用、面试也更常问的写法,因为能把异步代码写成"看起来同步"的形式,避免回调地狱

7. 定时器

  • steady_timer / deadline_timerasync_wait 的用法,以及取消定时器的语义

二、面试高频问题

  • Reactor vs Proactor 的区别,Asio 在 Linux 上如何用 epoll 模拟 Proactor
  • 为什么需要 strand?不用会有什么问题?
  • 一个异步 TCP echo server 怎么写(这是最常见的手写代码题)
  • 对象生命周期问题:异步操作还没完成,对象就析构了怎么办?(标准答案:用 shared_ptr + enable_shared_from_this,在回调里 shared_from_this() 延长生命周期)
  • io_context 单线程 vs 多线程模型的优劣,线程池模式怎么实现
  • 协程版本和回调版本的对比,为什么协程更受欢迎
  • 如何取消一个正在进行的异步操作

三、常见坑(写代码题时容易翻车的点)

  • Buffer 悬空:异步操作发起后立刻用局部变量做 buffer,函数返回后 buffer 已析构
  • 忘记 work guardio_context 没活干直接退出,回调根本没机会执行
  • 忘记 strand 导致 race condition:多线程下多个 handler 同时改共享状态
  • 对象生命周期this 指针在异步回调触发时已经失效

要不要准备?

如果面试的岗位涉及 C++ 后端、网络编程、中间件(比如高性能网关、RPC 框架、游戏服务器),基本必考,至少要能:

  1. 讲清楚 Proactor 模式和异步模型的原理
  2. 手写一个简单的异步 echo server(TCP)
  3. 讲清楚 strand 和对象生命周期管理这两个"资深"信号点

如果岗位偏业务/客户端,问到的概率低一些,但了解基本概念(io_context、async/await 模型)通常还是加分项。

可以针对某一块(比如 async echo server 的手写代码、或者协程写法 vs 回调写法的对比)