🕺🏻 gma999 🗓️ 2025-04-17 🎖️ 网络编程 🗂️ 博客剪藏 🏷️ #asio

【Boost】Asio 基本使用与核心设计思想_boost::asio-CSDN博客

声明

概述

基本了解

主要用于网络编程和底层I/O操作,支持同步异步操作,提供队列各种接口,从而帮助我们快速构建网路哦应用程序,目的就是简化I/O代码,提高性能和可维护性

主要特点总结

核心概念

o_service / io_contextio_service(在新版本中为 io_context)是 Boost.Asio 的核心组件,负责管理和调度所有异步操作。通过 io_service,可以注册异步操作,并在操作完成时通过回调函数得到通知

异步操作:Boost.Asio 提供的异步操作模型基于回调函数。开发者可以通过 async_ 系列函数(如 async_readasync_write 等)启动异步操作。这些操作不会阻塞线程,而是将操作提交给 io_service,并在操作完成时执行回调

套接字(Socket):Boost.Asio 提供了对 TCP 和 UDP 套接字的支持。TCP 套接字(tcp::socket)用于建立面向连接的通信,UDP 套接字(udp::socket)则用于无连接的通信。开发者可以通过这些类实现网络通信功能

常用接口与应用

boost::asio::io_context

主要作用

主要作用就是调用异步操作和处理这些操作的核心函数,内部提供了事件循环机制

常用方法总结

使用步骤总结

单任务循环

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

int main() {
    // 创建 io_context 对象
    boost::asio::io_context io_context;

    // 提交一个简单任务到 io_context
    io_context.post([]() {
        std::cout << "Hello, Boost.Asio!" << std::endl;
    });

    // 启动事件循环
    io_context.run();

    return 0;
}

多任务调度

int main()
{
    boost::asio::io_context io_context;

    io_context.post([](){
        std::cout<<"Hello,Boost.Asio"<<std::endl;
    });

    io_context.post([]() {
        std::cout << "Task 1" << std::endl;
    });

    io_context.post([]() {
        std::cout << "Task 2" << std::endl;
    });

    io_context.post([]() {
        std::cout << "Task 3" << std::endl;
    });

    io_context.run();

    return 0;
}

多线程共享一个io_context对象,实现并发处理

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

void worker(boost::asio::io_context& io_context, int id) {
    io_context.run();
    std::cout << "Thread " << id << " finished." << std::endl;
}

int main() {
    boost::asio::io_context io_context;

    // 提交任务
    for (int i = 0; i < 10; ++i) {
        io_context.post([i]() {
            std::cout << "Task " << i << " is running" << std::endl;
        });
    }

    // 创建线程池
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back(worker, std::ref(io_context), i);
    }

    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

boost::asio::ip::tcp::socket

处理 TCP 连接的类,用于发送和接收数据。它支持异步操作,可以在后台完成网络通信任务,而不会阻塞主线程

主要功能

常用方法

构造函数

成员函数

使用步骤

同步TCP客户端与服务端搭建

//
///TCP同步客户端
//

int main() {
    try {
        // 创建 io_context 和 socket
        boost::asio::io_context io_context;
        boost::asio::ip::tcp::socket socket(io_context);

        // 定义远程端点(IP 和端口)
        boost::asio::ip::tcp::endpoint endpoint(
            boost::asio::ip::address::from_string("127.0.0.1"), 8080);

        // 连接到服务器
        socket.connect(endpoint);

        // 发送数据到服务器
        std::string message = "Hello, Server!";
        boost::asio::write(socket, boost::asio::buffer(message));

        // 接收服务器响应
        char buffer[128];
        size_t len = socket.read_some(boost::asio::buffer(buffer));
        std::cout << "Server response: " << std::string(buffer, len) << std::endl;

        // 关闭连接
        socket.close();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}
//
///TCP同步服务器
//

int main() {
    try {
        boost::asio::io_context io_context;

        // 创建监听器
        boost::asio::ip::tcp::acceptor acceptor(
            io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8080));

        std::cout << "Server is running on port 8080..." << std::endl;

        // 接受客户端连接
        boost::asio::ip::tcp::socket socket(io_context);
        acceptor.accept(socket);

        std::cout << "Client connected: " << socket.remote_endpoint() << std::endl;

        // 接收客户端数据
        char buffer[128];
        size_t len = socket.read_some(boost::asio::buffer(buffer));
        std::cout << "Received: " << std::string(buffer, len) << std::endl;

        // 发送响应
        std::string response = "Hello, Client!";
        boost::asio::write(socket, boost::asio::buffer(response));

        // 关闭连接
        socket.close();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

异步TCP客户端与服务端搭建


//
///TCP异步服务器
//

void on_accept(const boost::system::error_code& ec, boost::asio::ip::tcp::socket socket) {
    if (!ec) {
        std::cout << "Client connected: " << socket.remote_endpoint() << std::endl;

        // 异步读取数据
        auto buffer = std::make_shared<std::vector<char>>(128);
        socket.async_read_some(boost::asio::buffer(*buffer),
            [buffer](const boost::system::error_code& ec, std::size_t length) {
                if (!ec) {
                    std::cout << "Received: " << std::string(buffer->data(), length) << std::endl;
                }
            });
    } else {
        std::cerr << "Accept failed: " << ec.message() << std::endl;
    }
}

int main() {
    boost::asio::io_context io_context;

    // 创建监听器
    boost::asio::ip::tcp::acceptor acceptor(
        io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8080));

    // 异步接受连接
    acceptor.async_accept(
        [&acceptor](const boost::system::error_code& ec, boost::asio::ip::tcp::socket socket) {
            on_accept(ec, std::move(socket));
        });

    std::cout << "Server is running on port 8080..." << std::endl;

    // 启动事件循环
    io_context.run();

    return 0;
}
//
///TCP异步步客户端
//

void on_connect(const boost::system::error_code& ec) {
    if (!ec) {
        std::cout << "Connected to server!" << std::endl;
    } else {
        std::cerr << "Failed to connect: " << ec.message() << std::endl;
    }
}

int main() {
    boost::asio::io_context io_context;
    boost::asio::ip::tcp::socket socket(io_context);

    // 定义远程端点
    boost::asio::ip::tcp::endpoint endpoint(
        boost::asio::ip::address::from_string("127.0.0.1"), 8080);

    // 异步连接
    socket.async_connect(endpoint, on_connect);

    // 运行事件循环
    io_context.run();

    return 0;
}

boost::asio::ip::tcp::acceptor

acceptor 类用于监听进入的 TCP 连接。它用于接受客户端发起的连接,并为每个连接创建一个新的 socket 实例

主要功能

构造函数

boost::asio::ip::tcp::acceptor(io_context, const endpoint&);
// 使用事例
boost::asio::io_context io_context;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 8080);
boost::asio::ip::tcp::acceptor acceptor(io_context, endpoint);

accept(socket):接收一个客户端连接请求,该方法是阻塞的直到客户端连接成功

boost::asio::ip::tcp::socket socket(io_context);
acceptor.accept(socket);  // 阻塞,直到有客户端连接

async_accept(socket , handler)

boost::asio::ip::tcp::socket socket(io_context);
acceptor.async_accept(socket, [](const boost::system::error_code& ec) {
    if (!ec) {
        std::cout << "Client connected successfully!" << std::endl;
    } else {
        std::cerr << "Error: " << ec.message() << std::endl;
    }
});
io_context.run();  // 运行事件循环,处理异步操作

local_endpoint()

boost::asio::ip::tcp::endpoint local_endpoint = acceptor.local_endpoint();
std::cout << "Server is listening on " << local_endpoint << std::endl;

close()

具体使用参考同步与异步服务器搭建

boost::asio::deadline_timer / steady_timer

这两个类是用于异步编程中的定时操作类,主要用于设置延时操作

主要功能

deadline_timer(基于绝对时间)

构造函数

boost::asio::deadline_timer(io_context, const boost::posix_time::ptime&);
boost::asio::deadline_timer(io_context, const boost::posix_time::time_duration&);

常用方法

具体使用

定时器1

#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

void handler(const boost::system::error_code& /*ec*/) {
    std::cout << "Deadline timer expired!" << std::endl;
}

int main() {
    try {
        boost::asio::io_context io_context;

        // 设置绝对到期时间(5秒后)
        boost::asio::deadline_timer timer(io_context, boost::posix_time::seconds(5));

        // 异步等待定时器到期
        timer.async_wait(handler);

        // 启动事件循环
        io_context.run();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

steady_timer(相对时间)

相对时间也就是到期时间是从当前时间开始的延迟

构造函数

boost::asio::steady_timer(io_context, const boost::chrono::steady_clock::duration&);

常用方法

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

void handler(const boost::system::error_code& /*ec*/) {
    std::cout << "Steady timer expired!" << std::endl;
}

int main() {
    try {
        boost::asio::io_context io_context;

        // 设置相对到期时间(5秒后)
        boost::asio::steady_timer timer(io_context, boost::asio::chrono::seconds(5));

        // 异步等待定时器到期
        timer.async_wait(handler);

        // 启动事件循环
        io_context.run();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

boost::asio::ip::tcp::resolver

resolver 是用来解析主机名和服务名的类。它将域名解析为具体的 IP 地址,用于建立连接

主要功能

主要功能

构造函数

boost::asio::ip::tcp::resolver(io_context);

常用方法

同步解析

int main() {
    try {
        boost::asio::io_context io_context;

        // 创建一个 resolver 对象
        boost::asio::ip::tcp::resolver resolver(io_context);

        // 同步解析主机名和服务名
        auto endpoints = resolver.resolve("example.com", "http");

        for (const auto& endpoint : endpoints) {
            std::cout << "Resolved endpoint: " << endpoint.endpoint() << std::endl;
        }

    } catch (const boost::system::system_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

异步解析

void on_resolve(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::results_type endpoints) {
    if (!ec) {
        for (const auto& endpoint : endpoints) {
            std::cout << "Resolved endpoint: " << endpoint.endpoint() << std::endl;
        }
    } else {
        std::cerr << "Resolve failed: " << ec.message() << std::endl;
    }
}

int main() {
    try {
        boost::asio::io_context io_context;

        // 创建 resolver 对象
        boost::asio::ip::tcp::resolver resolver(io_context);

        // 异步解析主机名和服务名
        resolver.async_resolve("example.com", "http", on_resolve);

        // 启动事件循环,等待解析完成
        io_context.run();

    } catch (const boost::system::system_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

boost::asio::buffer / mutable_buffer

bufferBoost.Asio 中用于封装数据块的类。它用于表示读写操作的数据区,支持多种数据类型(如数组、std::vectorstd::string

主要功能

Buffer

创建使用

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

int main() {
    std::vector<char> data(128);  // 创建一个存储 128 字节的 vector
    boost::asio::buffer(data);     // 使用 boost::asio::buffer() 创建一个缓冲区
    std::cout << "Buffer size: " << data.size() << std::endl;
    return 0;
}

mutable_buffer

表示一个可修改的数据缓冲区,表示可以修改缓冲区的数据,异步操作中一般用于读取缓冲区数据或者发送数据

构造函数

boost::asio::mutable_buffer buffer(void* data, std::size_t size);

测试

int main() {
    std::vector<char> data(128);  // 创建一个存储 128 字节的 vector
    boost::asio::mutable_buffer buffer(data.data(), data.size());  // 创建一个可修改的缓冲区
    std::cout << "Mutable buffer size: " << buffer.size() << std::endl;
    return 0;
}

boost::asio::streambuf

streambuf 是一个内存缓冲区类,提供了一个流接口来读写数据。它常用于处理异步读取的数据

主要功能

构造函数

boost::asio::streambuf buf;  // 创建一个空的 streambuf 对象

常用方法

异步读取数据

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

void read_handler(const boost::system::error_code& ec, std::size_t bytes_transferred) {
    if (!ec) {
        std::cout << "Successfully read " << bytes_transferred << " bytes." << std::endl;
    } else {
        std::cerr << "Error during read: " << ec.message() << std::endl;
    }
}

int main() {
    try {
        boost::asio::io_context io_context;

        boost::asio::ip::tcp::socket socket(io_context);
        boost::asio::ip::tcp::resolver resolver(io_context);
        auto endpoints = resolver.resolve("example.com", "http");

        // 连接到服务器
        boost::asio::connect(socket, endpoints);

        boost::asio::streambuf buf;  // 创建一个 streambuf 对象
        boost::asio::async_read(socket, buf, read_handler);  // 异步读取数据到 streambuf 中

        io_context.run();  // 启动事件循环
    } catch (const boost::system::system_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

异步写入数据

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

void write_handler(const boost::system::error_code& ec, std::size_t bytes_transferred) {
    if (!ec) {
        std::cout << "Successfully sent " << bytes_transferred << " bytes." << std::endl;
    } else {
        std::cerr << "Error during write: " << ec.message() << std::endl;
    }
}

int main() {
    try {
        boost::asio::io_context io_context;

        boost::asio::ip::tcp::socket socket(io_context);
        boost::asio::ip::tcp::resolver resolver(io_context);
        auto endpoints = resolver.resolve("example.com", "http");

        // 连接到服务器
        boost::asio::connect(socket, endpoints);

        // 将数据放入 streambuf
        boost::asio::streambuf buf;
        std::ostream os(&buf);
        os << "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";  // 向 buf 中写入 HTTP 请求

        // 异步写入数据
        boost::asio::async_write(socket, buf, write_handler);

        io_context.run();  // 启动事件循环
    } catch (const boost::system::system_error& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }

    return 0;
}

boost::asio::async_read() / write()

这两个函数用于异步地从 socket 读取数据或写入数据。它们支持回调机制,在操作完成时调用指定的回调函数

主要功能

接口在前面的事例中已经被广泛使用

boost::asio::async_read(socket, boost::asio::buffer(data), handler);  // 异步读取数据
boost::asio::async_write(socket, boost::asio::buffer(data), handler);  // 异步写入数据

boost::asio::connect() / async_connect()

connect 用于同步连接到远程主机,而 async_connect 用于异步连接,后者更常用于高性能网络编程

主要功能

boost::asio::async_connect(socket, endpoints, handler);

boost::asio::post()

post 是一个简单的异步任务调度器,它将任务投递到 io_context 中,任务会在 io_context.run() 循环中执行

主要功能

在事件循环中调度任务执行,类似于线程池的任务调度

boost::asio::post(io_context, [](){ std::cout << "Hello, Asio!" << std::endl; });

boost::asio::strand

strandBoost.Asio 中用于处理线程安全问题的类。在多线程环境中,它确保多个异步操作的回调函数不会同时执行,从而避免数据竞争和不一致性

主要功能

构造函数

boost::asio::strand<boost::asio::io_context::executor_type> strand(io_context.get_executor());

boost::asio::post(strand, handler)

boost::asio::post(strand, handler);  // 保证 handler 按顺序执行

strand 和 async_*

boost::asio::async_read(socket, buffer, strand.wrap(handler));  // wrap 使回调函数按顺序执行

strand保证回调顺序

///
///strand 保证回调顺序
///

void handler(int id) {
    std::cout << "Handler " << id << " executed in thread: "
              << std::this_thread::get_id() << std::endl;
}

int main() {
    boost::asio::io_context io_context;
    boost::asio::strand<boost::asio::io_context::executor_type> strand(io_context.get_executor());

    // 提交多个任务到同一个 strand,确保它们按顺序执行
    boost::asio::post(strand, std::bind(handler, 1));  // 提交任务1
    boost::asio::post(strand, std::bind(handler, 2));  // 提交任务2
    boost::asio::post(strand, std::bind(handler, 3));  // 提交任务3

    // 在多线程环境中运行 io_context
    std::thread t1([&io_context](){ io_context.run(); });
    std::thread t2([&io_context](){ io_context.run(); });

    t1.join();
    t2.join();

    return 0;
}

strand.wrap()

将异步操作的回调函数打包在一起,从而保证回调函数在同一strand中按照顺序执行,主要是在多线程中使用

boost::asio::async_read(socket, buffer, strand.wrap(handler));

strand.wrap() 保证顺序执行

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

void handler(int id) {
    std::cout << "Handler " << id << " executed in thread: "
              << std::this_thread::get_id() << std::endl;
}

int main() {
    boost::asio::io_context io_context;
    boost::asio::strand<boost::asio::io_context::executor_type> strand(io_context.get_executor());

    // 提交多个任务到同一个 strand,确保它们按顺序执行
    boost::asio::async_read_some(socket, buffer, strand.wrap(std::bind(handler, 1)));
    boost::asio::async_read_some(socket, buffer, strand.wrap(std::bind(handler, 2)));
    boost::asio::async_read_some(socket, buffer, strand.wrap(std::bind(handler, 3)));

    // 在多线程环境中运行 io_context
    std::thread t1([&io_context](){ io_context.run(); });
    std::thread t2([&io_context](){ io_context.run(); });

    t1.join();
    t2.join();

    return 0;
}

核心设计思想

异步模型与事件循环机制

整体逻辑

当调用一个异步操作的时候,io_service会启动事件循环

内部实现结合具体方法

post() 和 dispatch()

io_service/io_context

多线程与事件循环机制结合

多核机器上通过多核线程可以提高运行性能,多线程设计的核心之一就是确保其互相不会打扰,高效的执行异步任务,所以通过循环机制和任务队列。该处的核心思想可以参考modou网络库的设计思想

多路复用机制

asio中对于多路复用机制的使用在于确保在I/O操作时及时触发回调函数,不需要为每一个I/O操作都创建新的线程

strand设计

asio设计stand机制的核心目的就是保证异步编程中回调函数的顺序性,避免多个回调函数并发执行时的竞态条件。因为多线程环境中,多个异步操作的回调可能会在不同的线程中并发执行,那么就有可能造成数据不一致或者竞争情况

strand的核心作用就是让异步操作放入一个队列中,然后让其排队,从而确保同一strand中的回调函数按顺序执行,这样即使多个回调函数在被不同线程执行的时候,也不会出现竞态条件

核心特点:通过队列确保顺序性;通过事件循环机制执行任务,从而减少了锁的开销

拓展1:设计高效I/O复用机制,减少阻塞和提高吞吐量的思路

其他设计思想

之前学习modou网络库中接触并总结过这些思想,所以此处省略

Comment