课程导航学习路径 | Boost.System | Boost.Asio | Boost.Beast | Boost.JSON | Boost.MySQL

前置知识

  • C++ 基础(类、模板、异常处理)
  • 了解操作系统错误码概念(errno、GetLastError)

学习目标

完成本课程后,你将能够:

  1. 理解 error_code + error_category 的设计原理
  2. 掌握 I/O 操作中 错误码异常 两种错误处理模式
  3. 编写自定义 error_category
  4. 读懂 Hical 的跨平台错误码映射层

目录


1. 核心概念

1.1 为什么需要统一的错误码体系

C 语言 errno 的问题

  • 全局变量(即使 thread-local 化,仍然语义模糊)
  • 不同库对同一数值的含义不同
  • 跨平台差异:Windows 用 GetLastError() + WSAGetLastError(),POSIX 用 errno

C++ 异常 vs 错误码

特性异常 (exception)错误码 (error_code)
语法try/catch,代码清晰if 判断,稍显啰嗦
性能抛出时开销大几乎零开销
适用场景致命错误、配置错误可恢复的 I/O 错误
强制处理不强制(可能忘记 catch)不强制(可能忘记检查)

在网络编程中,connection_reseteof 等是常规事件,不是异常情况。如果每次断连都抛异常,性能开销不可接受。Boost.System 提供了统一的错误码体系,让这类场景可以用零开销的方式处理。

1.2 error_code 三要素

boost::system::error_code 由三个部分组成:

1
2
3
4
5
6
7
┌───────────────────────────────────┐
│         error_code                │
├───────────────────────────────────┤
│  value()    → int (错误码数值)     │
│  category() → error_category&     │
│  message()  → string (人类可读)    │
└───────────────────────────────────┘
  • value():整型错误码,不同 category 下相同数值含义不同
  • category():错误类别引用,决定数值的解释方式
  • message():调用 category().message(value()) 生成人类可读描述

关键特性

  • error_code 可以隐式转 bool——值为 0 表示无错误(false),非 0 表示有错误(true
  • error_code(默认构造)等同于 “无错误”

std::error_code 的关系

C++11 标准库吸收了 Boost.System 的设计,std::error_codeboost::system::error_code 接口几乎一致。Boost.Asio 使用 boost::system::error_code,但两者可以互转。

1.3 error_category 体系

Boost.System 预定义了两个核心 category:

Category说明来源
system_category()操作系统原生错误码Windows: GetLastError(),POSIX: errno
generic_category()POSIX 通用错误码跨平台统一(ECONNRESETETIMEDOUT 等)

为什么需要两个 category?

同一个 “连接被重置” 的错误:

  • 在 Linux 上:errno = ECONNRESET (104)
  • 在 Windows 上:WSAGetLastError() = WSAECONNRESET (10054)
  • 在 generic_category 中:统一为 errc::connection_reset
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
                   system_category()
                  ┌──────────────────┐
    Linux:        │ value = 104      │  → "Connection reset by peer"
    Windows:      │ value = 10054    │  → "Connection reset by peer"
                  └──────────────────┘

                   generic_category()
                  ┌──────────────────┐
    跨平台:       │ errc::connection │  → "Connection reset by peer"
                  │     _reset       │
                  └──────────────────┘

1.4 error_condition vs error_code

  • error_code:精确的、平台相关的错误(“Windows 错误码 10054”)
  • error_condition:可移植的错误条件(“连接被重置”)

error_code 可以与 error_condition 比较——这是跨平台判断错误类型的推荐方式:

1
2
3
4
5
6
7
boost::system::error_code ec = ...;  // 可能来自 Windows 或 Linux

// 跨平台判断:不管底层是 ECONNRESET 还是 WSAECONNRESET
if (ec == boost::asio::error::connection_reset)
{
    // 连接被重置
}

核心思想error_code 描述 “到底发生了什么”,error_condition 描述 “这类错误意味着什么”。


2. 基础用法

2.1 创建和检查 error_code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// example_error_code_basics.cpp
// 编译:g++ -std=c++20 example_error_code_basics.cpp -lboost_system -o example

#include <boost/system/error_code.hpp>
#include <boost/asio/error.hpp>
#include <iostream>

int main()
{
    // 1. 默认构造:无错误
    boost::system::error_code ok;
    std::cout << "ok: value=" << ok.value()
              << " bool=" << static_cast<bool>(ok)
              << " message=\"" << ok.message() << "\"\n";
    // 输出:ok: value=0 bool=0 message="Success"

    // 2. 从 Asio 错误常量构造
    boost::system::error_code eof = boost::asio::error::eof;
    std::cout << "eof: value=" << eof.value()
              << " bool=" << static_cast<bool>(eof)
              << " category=" << eof.category().name()
              << " message=\"" << eof.message() << "\"\n";
    // 输出:eof: value=2 bool=1 category=asio.misc message="End of file"

    // 3. 布尔判断(最常用)
    if (!ok)
    {
        std::cout << "ok 表示无错误\n";
    }
    if (eof)
    {
        std::cout << "eof 表示有错误: " << eof.message() << "\n";
    }

    // 4. 相等比较
    if (eof == boost::asio::error::eof)
    {
        std::cout << "确认是 EOF 错误\n";
    }

    return 0;
}

2.2 两种错误处理模式

模式 A:错误码参数(推荐用于可恢复错误)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 接受连接(错误码版本)
boost::system::error_code ec;
auto socket = acceptor.accept(ec);

if (ec == boost::asio::error::operation_aborted)
{
    // 服务器正在关闭,正常退出
    return;
}
if (ec)
{
    // 其他错误:记录日志并继续
    std::cerr << "Accept failed: " << ec.message() << "\n";
    continue;
}
// 成功:处理连接

模式 B:异常(适用于致命错误)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 接受连接(异常版本)——不传 error_code 参数
try
{
    auto socket = acceptor.accept();  // 失败时抛 system_error
    // 成功:处理连接
}
catch (const boost::system::system_error& e)
{
    // e.code() 返回 error_code
    // e.what() 返回错误描述
    std::cerr << "Fatal: " << e.what() << "\n";
    throw;  // 致命错误,向上传播
}

什么时候用哪种?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
                      这个错误可恢复吗?
                      ┌─────┴─────┐
                     是            否
                      │            │
               用 error_code    用异常 / system_error
               (继续运行)      (中止或向上传播)

    示例:                     示例:
    • 客户端断连               • SSL 证书加载失败
    • 读取超时                 • 端口已被占用
    • 临时资源不足             • 配置文件无效

2.3 常见错误码速查表

以下是 Boost.Asio 中最常遇到的错误码:

错误码常量含义典型触发场景
boost::asio::error::eof对端正常关闭连接读取时对方 close()
boost::asio::error::operation_aborted操作被取消定时器 cancel()、socket close()
boost::asio::error::connection_reset连接被对端重置对方进程崩溃
boost::asio::error::connection_refused连接被拒绝目标端口无服务监听
boost::asio::error::timed_out连接超时TCP 握手超时
boost::asio::error::address_in_use地址已被占用bind() 端口冲突
boost::asio::error::broken_pipe管道破裂向已关闭连接写入
boost::asio::error::would_block资源暂时不可用非阻塞 I/O 无数据
boost::asio::error::no_descriptors文件描述符不足连接数超系统限制
boost::asio::error::access_denied权限不足bind() 特权端口

3. 进阶主题

3.1 自定义 error_category

当你的应用有自己的错误码体系时,可以扩展 Boost.System:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// example_custom_category.cpp
// 编译:g++ -std=c++20 example_custom_category.cpp -lboost_system -o example

#include <boost/system/error_code.hpp>
#include <iostream>
#include <string>

// 第一步:定义错误码枚举
enum class HttpError
{
    hOk = 0,
    hBadRequest = 400,
    hUnauthorized = 401,
    hForbidden = 403,
    hNotFound = 404,
    hInternalServerError = 500,
};

// 第二步:实现 error_category 子类
class HttpErrorCategory : public boost::system::error_category
{
public:
    const char* name() const noexcept override
    {
        return "http";
    }

    std::string message(int ev) const override
    {
        switch (static_cast<HttpError>(ev))
        {
            case HttpError::hOk:
                return "OK";
            case HttpError::hBadRequest:
                return "Bad Request";
            case HttpError::hUnauthorized:
                return "Unauthorized";
            case HttpError::hForbidden:
                return "Forbidden";
            case HttpError::hNotFound:
                return "Not Found";
            case HttpError::hInternalServerError:
                return "Internal Server Error";
            default:
                return "Unknown HTTP error";
        }
    }
};

// 第三步:全局单例(保证地址唯一)
const HttpErrorCategory& httpCategory()
{
    static HttpErrorCategory instance;
    return instance;
}

// 第四步:make_error_code 重载(启用隐式转换)
boost::system::error_code make_error_code(HttpError e)
{
    return {static_cast<int>(e), httpCategory()};
}

// 第五步:特化 is_error_code_enum(启用枚举 → error_code 自动转换)
namespace boost::system
{
    template <>
    struct is_error_code_enum<HttpError> : std::true_type
    {
    };
} // namespace boost::system

int main()
{
    // 枚举自动转换为 error_code
    boost::system::error_code ec = HttpError::hNotFound;

    std::cout << "category: " << ec.category().name() << "\n";   // "http"
    std::cout << "value:    " << ec.value() << "\n";              // 404
    std::cout << "message:  " << ec.message() << "\n";            // "Not Found"
    std::cout << "is error: " << static_cast<bool>(ec) << "\n";   // 1

    // 可以和其他 error_code 统一处理
    if (ec)
    {
        std::cout << "错误 [" << ec.category().name() << ":"
                  << ec.value() << "] " << ec.message() << "\n";
    }

    return 0;
}

3.2 跨平台错误码映射

同一个网络错误在不同平台上有不同的数值:

错误含义POSIX errnoWindows WSA
连接重置ECONNRESET (104)WSAECONNRESET (10054)
连接拒绝ECONNREFUSED (111)WSAECONNREFUSED (10061)
连接超时ETIMEDOUT (110)WSAETIMEDOUT (10060)
地址占用EADDRINUSE (98)WSAEADDRINUSE (10048)
网络不可达ENETUNREACH (101)WSAENETUNREACH (10051)

Boost.Asio 的错误常量(如 boost::asio::error::connection_reset)已经做了平台抽象,直接用 Asio 常量比较是最安全的跨平台方式

但如果你需要处理 system_category()generic_category() 下的原始系统错误,就必须自己做映射——这正是 Hical 的 Error.cpp 所做的事情。


4. Hical 实战解读

4.1 Error.h:框架级错误码枚举

源码:src/core/Error.h

Hical 不直接向上层暴露 Boost 错误码,而是定义了框架自己的错误码枚举

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
enum class ErrorCode : uint32_t
{
    hNoError = 0,

    // ============ 连接错误 ============
    hEof,                  // 对端正常关闭
    hConnectionReset,      // 连接被重置
    hConnectionRefused,    // 连接被拒绝
    hTimedOut,             // 连接超时
    // ...

    // ============ SSL/TLS 错误 ============
    hSslHandshakeError,    // SSL 握手失败
    hSslInvalidCertificate,
    hSslProtocolError,

    hUnknown = 0xFFFF
};

设计思路

  • 上层业务代码不直接依赖 boost::system::error_code
  • 所有 Boost 错误先经过 fromBoostError() 转换为框架错误码
  • 好处:如果未来替换底层网络库(如换掉 Asio),上层代码无需修改

同时还封装了 NetworkError 结构体,组合错误码和描述信息,并提供便捷查询方法(isEof()isCancelled()):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
struct NetworkError
{
    ErrorCode code {ErrorCode::hNoError};
    std::string message;

    explicit operator bool() const { return code != ErrorCode::hNoError; }
    bool ok() const { return code == ErrorCode::hNoError; }
    bool isEof() const { return code == ErrorCode::hEof; }
    bool isCancelled() const { return code == ErrorCode::hOperationAborted; }
};

4.2 Error.cpp:fromBoostError 跨平台映射

源码:src/core/Error.cpp:11-153

这是本课程的核心示范——如何构建一个生产级的跨平台错误码映射层

第一层映射:Asio 错误常量Error.cpp:18-78

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
ErrorCode fromBoostError(const boost::system::error_code& ec)
{
    if (!ec)
        return ErrorCode::hNoError;

    // Asio 提供的跨平台错误常量,直接匹配
    if (ec == boost::asio::error::eof)
        return ErrorCode::hEof;
    if (ec == boost::asio::error::connection_reset)
        return ErrorCode::hConnectionReset;
    if (ec == boost::asio::error::operation_aborted)
        return ErrorCode::hOperationAborted;
    // ...
}

要点boost::asio::error::xxx 是跨平台的,优先用它们做比较。

第二层映射:系统原始错误码Error.cpp:80-150

当 Asio 常量无法覆盖时,回退到平台相关的原始值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
auto value = ec.value();
auto& category = ec.category();

if (category == boost::system::system_category()
    || category == boost::system::generic_category())
{
#ifdef _WIN32
    switch (value)
    {
        case WSAECONNRESET:    return ErrorCode::hConnectionReset;
        case WSAECONNREFUSED:  return ErrorCode::hConnectionRefused;
        case WSAETIMEDOUT:     return ErrorCode::hTimedOut;
        // ...
    }
#else
    switch (value)
    {
        case ECONNRESET:       return ErrorCode::hConnectionReset;
        case ECONNREFUSED:     return ErrorCode::hConnectionRefused;
        case ETIMEDOUT:        return ErrorCode::hTimedOut;
        // ...
    }
#endif
}

return ErrorCode::hUnknown;  // 未知错误

要点:这里用了 #ifdef _WIN32 条件编译,因为 WSAECONNRESETECONNRESET 是不同平台的宏。

映射流程图

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
boost::system::error_code
    ├─ 匹配 Asio 常量? ──→ 是 ──→ 直接返回对应 ErrorCode
    └─ 否 ──→ 检查 category 是 system 或 generic?
              ├─ Windows ──→ switch(WSA 错误码)
              └─ POSIX   ──→ switch(errno 值)
              └─ 都不匹配 ──→ ErrorCode::hUnknown

4.3 错误码在连接管理中的使用

场景 1:定时器回调中的 error_code

源码:src/asio/AsioTimer.cpp

定时器的 async_wait 回调会收到一个 error_code 参数:

  • !ec(无错误)= 定时器正常到期,执行回调
  • ec == operation_aborted = 定时器被 cancel() 了,不执行回调

场景 2:Accept 循环中的 system_error 异常

源码:src/core/HttpServer.cpp:170-202

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Awaitable<void> HttpServer::acceptLoop()
{
    while (running_.load())
    {
        try
        {
            // 协程式 async_accept 在失败时抛 system_error
            auto socket = co_await acceptor_->async_accept(
                boost::asio::use_awaitable);
            // ...
        }
        catch (const boost::system::system_error& e)
        {
            if (e.code() == boost::asio::error::operation_aborted
                || e.code() == boost::asio::error::bad_descriptor)
            {
                break;  // 服务器正在关闭,正常退出循环
            }
            // 其他错误(如 EMFILE):忽略并继续接受
        }
    }
}

要点:协程模式下,Asio 默认抛异常(因为没有传 error_code 参数的地方)。所以必须用 try/catch 包裹。

场景 3:HTTP 请求处理中的错误分支

源码:src/core/HttpServer.cpp:331-348

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
catch (const beast::system_error& e)
{
    if (e.code() == http::error::body_limit)
    {
        // 请求体超过限制 → 返回 413
    }
    else if (e.code() != beast::errc::not_connected
             && e.code() != boost::asio::error::eof)
    {
        // 忽略正常关闭,只处理异常错误
    }
}

4.4 设计模式总结

Hical 中错误处理的经验法则:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
                      错误类型?
               ┌────────┴────────┐
            I/O 操作            配置 / 初始化
               │                    │
         协程中?                用异常
        ┌───┴───┐              (SslContext 加载证书
       是       否              acceptor bind 端口)
        │        │
   try/catch   error_code 参数
   (system_     (定时器回调)
    error)
场景错误处理方式示例
协程中的异步 I/Otry/catch system_errorco_await async_accept()
回调中的异步 I/Oerror_code 参数检查timer.async_wait([](ec) { ... })
同步操作(可恢复)error_code 输出参数socket.close(ec)
配置 / 初始化错误抛异常向上传播证书加载失败

5. 练习题

练习 1:error_code 基础

编写一个程序,使用 boost::asio::ip::tcp::resolver 解析域名。分别演示:

  • 解析 "www.google.com" 成功时 error_code 的状态
  • 解析一个不存在的域名(如 "this.domain.does.not.exist.invalid")失败时的 error_code

提示:使用 resolver.resolve(host, service, ec) 的 error_code 重载版本。

练习 2:自定义 error_category

定义一个 GameErrorCategory,包含以下错误码:

  • PlayerNotFound = 1
  • InventoryFull = 2
  • InsufficientGold = 3
  • LevelTooLow = 4

实现完整的 error_categorymake_error_codeis_error_code_enum 特化,并在 main 中演示使用。

练习 3:阅读源码

阅读 Hical 的 src/core/Error.cpp,回答以下问题:

  1. fromBoostError() 为什么要做两层映射(先 Asio 常量,再平台原始值)?
  2. 如果 error_code 的 category 既不是 system_category 也不是 generic_category(比如 SSL 错误),会返回什么?
  3. toNetworkError() 函数的 message 字段来自哪里?

参考答案

练习 1 参考答案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <boost/asio.hpp>
#include <iostream>

int main()
{
    boost::asio::io_context ioCtx;
    boost::asio::ip::tcp::resolver resolver(ioCtx);
    boost::system::error_code ec;

    // 成功解析
    auto results = resolver.resolve("www.google.com", "80", ec);
    if (!ec)
    {
        std::cout << "解析成功,error_code: " << ec.message() << std::endl;
        for (const auto& entry : results)
        {
            std::cout << "  " << entry.endpoint() << std::endl;
        }
    }

    // 失败解析
    resolver.resolve("this.domain.does.not.exist.invalid", "80", ec);
    if (ec)
    {
        std::cout << "解析失败" << std::endl;
        std::cout << "  value:    " << ec.value() << std::endl;
        std::cout << "  category: " << ec.category().name() << std::endl;
        std::cout << "  message:  " << ec.message() << std::endl;
        // 典型输出:value=11003 (Windows) 或 value=-2 (Linux)
        //          message: "Host not found (non-authoritative)" 或 "Name or service not known"
    }

    return 0;
}
// 编译: g++ -std=c++20 -O2 ex1.cpp -lboost_system -lpthread -o ex1

要点:同一个"域名不存在"错误在 Windows 和 Linux 上的 value 不同(Windows 用 WSAHOST_NOT_FOUND=11001,Linux 用 EAI_NONAME=-2),但都可以通过 ec.message() 获取人类可读描述。这正是 error_code 的 category 机制的价值——同一个语义在不同平台有不同的数值表示。

练习 2 参考答案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <boost/system/error_code.hpp>
#include <iostream>
#include <string>

// 1. 定义错误码枚举
enum class GameError
{
    PlayerNotFound = 1,
    InventoryFull = 2,
    InsufficientGold = 3,
    LevelTooLow = 4
};

// 2. 实现 error_category
class GameErrorCategory : public boost::system::error_category
{
public:
    const char* name() const noexcept override
    {
        return "game";
    }

    std::string message(int ev) const override
    {
        switch (static_cast<GameError>(ev))
        {
            case GameError::PlayerNotFound:   return "Player not found";
            case GameError::InventoryFull:    return "Inventory is full";
            case GameError::InsufficientGold: return "Insufficient gold";
            case GameError::LevelTooLow:      return "Level too low";
            default:                          return "Unknown game error";
        }
    }
};

// 3. 全局单例
inline const GameErrorCategory& gameCategory()
{
    static GameErrorCategory instance;
    return instance;
}

// 4. make_error_code 自由函数
inline boost::system::error_code make_error_code(GameError e)
{
    return {static_cast<int>(e), gameCategory()};
}

// 5. is_error_code_enum 特化——让 error_code 能隐式从 GameError 构造
namespace boost::system
{
    template <>
    struct is_error_code_enum<GameError> : std::true_type {};
}

int main()
{
    // 隐式转换:GameError → error_code
    boost::system::error_code ec = GameError::InventoryFull;

    std::cout << "category: " << ec.category().name() << std::endl;  // "game"
    std::cout << "value:    " << ec.value() << std::endl;            // 2
    std::cout << "message:  " << ec.message() << std::endl;          // "Inventory is full"
    std::cout << "bool:     " << (ec ? "true" : "false") << std::endl; // "true"

    // 无错误
    boost::system::error_code ok;
    std::cout << "ok bool:  " << (ok ? "true" : "false") << std::endl; // "false"

    // 在条件判断中使用
    ec = GameError::LevelTooLow;
    if (ec)
    {
        std::cout << "操作失败: " << ec.message() << std::endl;
    }

    return 0;
}

要点

  • error_category 是单例(static 局部变量),所有同类错误码共享一个 category 对象
  • is_error_code_enum 特化使 error_code ec = GameError::InventoryFull 隐式调用 make_error_code
  • 这个模式与 Hical 的 ErrorCode 枚举 + fromBoostError() 映射层设计思路一致

练习 3 参考答案

Q1:fromBoostError() 为什么要做两层映射?

因为 Boost.Asio 的 error_code 来自两种不同的 category:

  • 第一层(Asio 常量):boost::asio::error::eofboost::asio::error::connection_reset 等,这些是 Asio 自定义的跨平台错误枚举,值在所有平台一致。优先匹配它们效率最高。
  • 第二层(平台原始值):某些错误 Asio 不提供跨平台常量,只通过 system_category()generic_category() 返回操作系统的原始错误码(如 Linux 的 ECONNRESET=104、Windows 的 WSAECONNRESET=10054)。第二层用 #ifdef _WIN32 分支处理这些差异。

如果只做第一层,一些平台特有的错误码无法被识别;如果只做第二层,就要为每个平台分别写所有映射。两层配合是最完整的覆盖策略。

Q2:如果 category 既不是 system_category 也不是 generic_category,会返回什么?

返回 ErrorCode::hUnknown(值 0xFFFF)。函数末尾的兜底 return ErrorCode::hUnknown; 处理了所有未匹配的情况。SSL 错误的 category 是 boost::asio::error::get_ssl_category(),它不在前两层的匹配范围内,但如果其 value() 恰好匹配了第一层的某些 Asio 常量(如 operation_aborted),仍然可以被正确映射。

Q3:toNetworkError()message 字段来自哪里?

来自 boost::system::error_code::message() 方法——即操作系统原始的错误描述字符串。例如 Linux 上 ECONNRESET 返回 "Connection reset by peer",Windows 上 WSAECONNRESET 返回 "An existing connection was forcibly closed by the remote host"。这个描述比框架的 errorCodeToString() 更详细(后者返回统一的英文描述),两者互补。


6. 总结与拓展阅读

核心要点

概念要点
error_code值 + 类别 + 描述,可隐式转 bool
error_category解释错误码含义的上下文
system_error包裹 error_code 的异常类
error_condition可移植的错误条件,用于跨平台比较

拓展阅读

下一步

error_code 是 Asio 一切异步操作的基础返回值。在 课程 2: Boost.Asio 中,你将看到 error_code 如何在 async_readasync_writeasync_accept 等操作中被实际使用。