0
点赞
收藏
分享

微信扫一扫

Boost.Asio C++ 网络库

一、什么是boost.asio

Boost.Asio是Boost C++库中的一个组件主要用于:

网络编程(TCP/UDP)

异步 I/O 操作

定时器

串口通信(通过 boost::asio::serial_port)

文件 I/O(有限支持)

它基于 Proactor 模式,使用回调函数或协程来处理异步操作。

Proactor 模式是 异步 I/O 编程 中的一种设计模式,广泛应用于高性能网络服务器和系统编程中,特别是在使用像 Boost.Asio、libevent、Windows I/O Completion Ports (IOCP) 等异步 I/O 框架时。

io_context :核心调度器,管理所有异步操作

socket :表示 TCP 或 UDP 套接字

async_read, async_write: 异步读写操作

async_wait :定时器等待

resolver: DNS 解析器

strand :保证线程安全的顺序执行

deadline_timer, steady_timer :定时器

以下是TCP客户端示例(同步)

#include <boost/asio.hpp>   // Boost.Asio 主要头文件,包含网络、I/O 等功能
#include <iostream>        // 标准输入输出流,用于打印响应内容

int main() {
    // 创建 io_context 对象
    // 这是 Boost.Asio 的核心类,负责管理 I/O 操作的调度(事件循环)
    boost::asio::io_context io;

    // 创建一个 TCP 套接字对象
    // 所有数据的发送和接收都通过这个 socket 对象完成
    boost::asio::ip::tcp::socket socket(io);

    // 创建一个解析器 resolver
    // 用于将主机名(域名)和端口号转换成具体的 IP 地址和端口
    boost::asio::ip::tcp::resolver resolver(io);

    // 使用 resolver 解析 "example.com" 和服务 "http"(即端口 80)
    // 返回一个 endpoint 迭代器列表,然后使用 connect 函数连接到第一个有效的地址
    boost::asio::connect(socket, resolver.resolve("example.com", "http"));

    // 构造 HTTP 请求报文
    std::string request = 
        "GET / HTTP/1.1\r\n"
        "Host: example.com\r\n"
        "Connection: close\r\n"
        "\r\n";

    // 将请求发送到服务器
    // boost::asio::buffer() 将字符串包装成缓冲区格式
    // write() 函数会阻塞直到所有数据被写入 socket
    boost::asio::write(socket, boost::asio::buffer(request));

    // 创建一个字符数组作为接收缓冲区,大小为 4096 字节
    char response[4096];

    // 从 socket 中读取响应数据
    // read_some() 是同步函数,会阻塞直到收到一些数据
    // 返回值 len 表示实际读取的字节数
    size_t len = socket.read_some(boost::asio::buffer(response));

    // 将收到的数据写入标准输出(控制台),显示服务器返回的内容
    std::cout.write(response, len);

    return 0;
}

CP客户端示例(异步)

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

using boost::asio::ip::tcp;

int main() 
{
    try {
        // 创建 io_context 对象,它是所有异步操作的核心调度器
        boost::asio::io_context io;

        // 使用智能指针管理 socket 生命周期,防止异步回调中访问已销毁对象
        auto socket = std::make_shared<tcp::socket>(io);

        // 创建解析器 resolver,用于将域名和端口解析为 IP 地址
        tcp::resolver resolver(io);

        // 解析目标地址:example.com:80 (HTTP)
        // 注意:resolve 是同步的,实际项目中也可以改为异步 resolve
        auto endpoints = resolver.resolve("example.com", "http");

        // 异步连接到服务器
        boost::asio::async_connect(*socket, endpoints,
            [socket](const boost::system::error_code& ec, const tcp::endpoint&) {
                if (ec)
                {
                    std::cerr << "连接失败: " << ec.message() << std::endl;
                    return;
                }

                std::cout << "连接成功,正在发送 HTTP 请求..." << std::endl;

                // 构造 HTTP 请求报文
                std::string request =
                    "GET / HTTP/1.1\r\n"
                    "Host: example.com\r\n"
                    "Connection: close\r\n"
                    "\r\n";

                // 异步发送请求数据
                boost::asio::async_write(*socket, boost::asio::buffer(*request.c_str(), request.size()),
                    [socket](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) 
                    {
                        if (ec)
                        {
                            std::cerr << "发送请求失败: " << ec.message() << std::endl;
                            return;
                        }

                        std::cout << "请求已发送,等待响应..." << std::endl;

                        // 准备接收缓冲区
                        auto response = std::make_shared<std::vector<char>>(4096);

                        // 异步读取响应数据
                        socket->async_read_some(boost::asio::buffer(*response),
                            [socket, response](const boost::system::error_code& ec, std::size_t len) 
                            {
                                if (ec)
                                {
                                    std::cerr << "接收响应失败: " << ec.message() << std::endl;
                                    return;
                                }

                                std::cout << "收到响应数据:" << std::endl;
                                std::cout.write(response->data(), static_cast<std::streamsize>(len));
                                std::cout << std::endl;
                            });
                    });
            });

        // 启动异步事件循环,开始处理异步操作
        io.run();
    }
    catch (std::exception& e) {
        std::cerr << "异常: " << e.what() << std::endl;
    }

    return 0;
}

boost::asio::io_context: 所有异步操作的调度核心

async_connect() :异步连接服务器,完成后调用回调函数

async_write() :异步发送 HTTP 请求

async_read_some() :异步读取服务器返回的数据

shared_ptr<socket>: 防止在异步回调执行前 socket 被销毁

main()
   ↓
创建 io_context + socket + resolver
   ↓
resolver.resolve("example.com", "http")
   ↓
async_connect(socket, endpoint)
   ↓
[连接成功] → async_write(request)
   ↓
[发送完成] → async_read_some(response)
   ↓
[接收完成] → 输出响应内容

C++ 11中可以使用std::bind 来简化参数绑定、避免手动捕获上下文或重复传参

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <functional> // std::bind, std::placeholders

// 使用 boost.asio 的 tcp 命名空间
using boost::asio::ip::tcp;
// 使用占位符 _1, _2 等,用于回调参数绑定
namespace placeholders = std::placeholders;

/**
 * 连接完成后的回调函数
 */
void handle_connect(const boost::system::error_code& ec, 
                    tcp::socket* socket,               // 套接字指针
                    const std::string& request,         // HTTP 请求内容
                    std::shared_ptr<std::vector<char>> buffer) 
                    { // 接收缓冲区
    if (ec)
    {
        std::cerr << "连接失败: " << ec.message() << std::endl;
        return;
    }

    std::cout << "连接成功,正在发送 HTTP 请求..." << std::endl;

    // 异步写入 HTTP 请求数据
    boost::asio::async_write(*socket, boost::asio::buffer(request),
        std::bind(&handle_write, placeholders::_1, placeholders::_2, socket, buffer));
}

/**
 * 发送请求完成后的回调函数
 */
void handle_write(const boost::system::error_code& ec,
                  std::size_t /*bytes_transferred*/,  // 已发送字节数(未使用)
                  tcp::socket* socket,                // 套接字指针
                  std::shared_ptr<std::vector<char>> buffer) // 接收缓冲区
                  {
    if (ec)
    {
        std::cerr << "发送请求失败: " << ec.message() << std::endl;
        return;
    }

    std::cout << "请求已发送,等待响应..." << std::endl;

    // 异步读取服务器返回的数据
    socket->async_read_some(boost::asio::buffer(*buffer),
        std::bind(&handle_read, placeholders::_1, placeholders::_2, buffer));
}

/**
 * 接收响应数据后的回调函数
 */
void handle_read(const boost::system::error_code& ec,
                 std::size_t len,                      // 实际读取到的字节数
                 std::shared_ptr<std::vector<char>> buffer) 
                 { // 接收缓冲区
    if (ec)
    {
        std::cerr << "接收响应失败: " << ec.message() << std::endl;
        return;
    }

    std::cout << "收到响应数据:" << std::endl;
    // 打印接收到的数据
    std::cout.write(buffer->data(), static_cast<std::streamsize>(len));
    std::cout << std::endl;
}

int main()
{
    try {
        // 创建 io_context 对象,是所有异步操作的核心调度器
        boost::asio::io_context io;

        // 使用智能指针管理 socket 生命周期,防止异步回调中访问已销毁对象
        auto socket = std::make_shared<tcp::socket>(io);

        // 分配一个大小为 4096 的缓冲区用于接收响应数据
        auto buffer = std::make_shared<std::vector<char>>(4096);

        // 构造 HTTP GET 请求报文
        std::string request =
            "GET / HTTP/1.1\r\n"
            "Host: example.com\r\n"
            "Connection: close\r\n"   // 表示请求完成后关闭连接
            "\r\n";                   // 请求头结束标志

        // 创建解析器 resolver,用于将域名和端口解析为 IP 地址
        tcp::resolver resolver(io);

        // 解析目标地址:example.com:80 (HTTP)
        auto endpoints = resolver.resolve("example.com", "http");

        // 异步连接到服务器
        boost::asio::async_connect(*socket, endpoints,
            std::bind(handle_connect, placeholders::_1, socket.get(), request, buffer));

        std::cout << "启动事件循环..." << std::endl;

        // 启动异步事件循环,开始处理异步操作
        io.run();
    }
    catch (std::exception& e) 
    {
        // 捕获并打印异常信息
        std::cerr << "异常: " << e.what() << std::endl;
    }

    return 0;
}

main()
   ↓
创建 io_context + socket + buffer + resolver
   ↓
resolver.resolve("example.com", "http")
   ↓
async_connect(...) → 触发 handle_connect
   ↓
handle_connect()
   ↓
async_write(...) → 触发 handle_write
   ↓
handle_write()
   ↓
async_read_some(...) → 触发 handle_read
   ↓
handle_read() → 输出响应内容

二、std::bind 与boost::asio::connect /boost:;asio::async_connect的区别

类别 std::bind                        connect                                               async_connect

类型 标准库函数模板            Boost.Asio 同步函数                             Boost.Asio 异步函数

作用 绑定函数和参数,生成可调用对象 同步连接服务器 异步连接服务器

是否阻塞主线程 ❌ 不涉及线程,只是绑定参数 ✅ 是(同步) ❌ 否(异步)

何时使用 配合异步回调使用 快速建立同步连接 建立非阻塞连接,配合回调

底层机制 C++11 特性,用于函数封装 直接调用系统 connect 使用 io_context 异步调度

示例代码片段 std::bind(func, _1, obj) connect(socket, endpoints) async_connect(socket, endpoints, handler)

举报

相关推荐

0 条评论