Asio C++零基础入门(一):Asio C++库详细介绍
什么是Asio C++库?
Asio(Asynchronous I/O 的缩写)是一个专为网络和低级I/O编程设计的跨平台C++库,其核心目标是提供一套一致、高效的异步编程模型,帮助开发者构建高性能、可扩展的并发应用程序。该库由澳大利亚软件工程师Christopher M. Kohlhoff于2003年首次开发,最初作为独立项目发布,2005年正式纳入Boost库生态系统(成为Boost.Asio),此后逐渐成为C++异步编程领域的事实标准之一。如今,Asio不仅是Boost库的核心组件,还提供独立分发版本(Standalone Asio),开发者可根据项目需求选择是否依赖Boost生态。
在计算机科学领域,I/O操作(尤其是网络I/O)往往是应用程序性能的瓶颈。传统同步I/O模型中,一个线程对应一个I/O操作,当操作未完成时线程会处于阻塞状态,导致系统资源(线程、内存)被大量占用,难以应对高并发场景(如万级以上网络连接)。Asio的出现正是为了解决这一痛点——它基于操作系统底层的异步I/O机制(如Linux的epoll、Windows的IOCP、macOS的kqueue),通过“事件驱动”模式实现单线程(或少量线程)处理大量并发I/O操作,从根本上避免了线程创建、上下文切换的开销,同时简化了并发逻辑的开发难度。
值得注意的是,Asio并非仅面向网络编程,其设计理念是“将所有I/O操作抽象为异步事件”,因此除了TCP/UDP等网络功能,还支持串口通信、定时器、信号处理等低级I/O场景,形成了一套统一的异步编程范式。
Asio的核心特性
Asio的强大之处在于其精心设计的核心特性,这些特性既满足了高性能需求,又兼顾了开发效率和跨平台兼容性:
1. 多范式的异步模型
Asio支持三种主流的异步编程范式,开发者可根据项目复杂度和团队习惯灵活选择:
- 回调函数(Callback-based):最基础的异步模式,通过传递函数对象(如
std::function、lambda表达式)作为操作完成后的处理逻辑。适用于简单场景,代码直观但嵌套较深时易出现“回调地狱”(Callback Hell)。 - Future/Promise:基于C++11标准的
std::future和std::promise,将异步操作的结果封装为“未来值”,通过get()方法阻塞获取结果或wait_for()非阻塞检查状态。适用于需要同步等待结果的场景,代码线性度优于回调。 - 协程(Coroutine):支持C++20标准协程(通过
co_await、co_return关键字),可将异步代码写成“同步风格”,彻底消除回调嵌套,同时保持异步的高效性。这是Asio推荐的高级模式,也是现代C++异步编程的发展方向。
2. 全面的网络功能
Asio提供了对主流网络协议的完整支持,且接口设计符合POSIX套接字习惯,降低了开发者的学习成本:
- TCP协议:支持客户端(
ip::tcp::socket)和服务器(ip::tcp::acceptor)开发,包含连接建立、数据收发、连接关闭等全流程操作,支持IPv4和IPv6双栈。 - UDP协议:通过
ip::udp::socket实现无连接的数据报通信,支持广播、多播(Multicast)等高级特性,适用于低延迟、高吞吐量的场景(如实时音视频、游戏)。 - ICMP协议:支持ICMP消息(如ping请求)的发送和接收,可用于网络连通性检测工具开发。
- 其他特性:支持域名解析(
ip::tcp::resolver)、SSL/TLS加密(需结合Boost.SSL或OpenSSL)、Socket选项配置(如SO_REUSEADDR、TCP_NODELAY)等。
3. 高精度定时器
定时器是异步编程中的核心组件,Asio提供了三种定时器类型,满足不同时间精度和使用场景:
steady_timer:基于“稳定时钟”(Steady Clock),时钟频率不受系统时间调整影响(如用户修改系统时间、NTP同步),适用于需要精确间隔的场景(如定时任务、超时控制)。system_timer:基于“系统时钟”(System Clock),时钟时间与系统当前时间一致,适用于需要与系统时间关联的场景(如定时在每天凌晨执行任务)。high_resolution_timer:基于“高精度时钟”(High-resolution Clock),提供最高精度的时间测量(通常可达纳秒级),适用于对时间精度要求极高的场景(如性能基准测试)。
所有定时器均支持异步等待(async_wait),并可通过cancel()方法取消未触发的定时任务,灵活性极高。
4. 串行端口通信
Asio对串行端口(Serial Port)的支持覆盖了主流操作系统,提供了与网络Socket一致的异步编程接口,简化了跨平台串口应用的开发:
- 支持Windows的COM口、Linux/macOS的
/dev/tty设备。 - 可配置串口参数:波特率(Baud Rate)、数据位(Data Bits)、停止位(Stop Bits)、校验位(Parity)、流控制(Flow Control)等。
- 支持异步读写操作,可用于嵌入式设备通信、工业控制(如PLC)、硬件调试等场景。
5. 操作系统信号处理
Asio允许开发者以异步方式处理操作系统信号(如SIGINT、SIGTERM),避免了传统信号处理函数的局限性(如不可重入、只能调用有限函数):
- 通过
signal_set类注册需要监听的信号。 - 当信号触发时,异步调用预先设置的处理函数,可安全地执行资源释放、程序退出等逻辑。
- 支持信号的添加、移除和取消,适用于服务端程序的优雅关闭(如接收
SIGTERM后停止监听新连接、处理完现有请求再退出)。
6. 跨平台兼容性
Asio的设计目标之一是“一次编写,多平台运行”,其底层适配了主流操作系统的I/O模型:
- Linux:基于epoll(边缘触发/水平触发)实现高效事件通知。
- Windows:基于IOCP(I/O Completion Port)实现异步I/O,支持重叠I/O(Overlapped I/O)。
- macOS/iOS:基于kqueue实现事件驱动,同时支持select/poll作为 fallback。
- 其他系统:支持FreeBSD、Solaris等类Unix系统,以及嵌入式Linux(如ARM架构)。
开发者无需关注底层操作系统差异,只需使用Asio提供的统一接口,即可确保代码在不同平台上的一致性和高效性。
7. 可扩展的I/O执行策略
Asio的核心调度器(io_context)支持自定义I/O执行策略,允许开发者根据应用场景优化性能:
- 单线程执行:单个
io_context在一个线程中运行,适用于I/O密集型场景,避免线程同步开销。 - 多线程执行:多个线程同时调用
io_context::run(),实现“线程池”模式,适用于I/O操作中包含少量计算的场景,充分利用多核CPU。 strand序列化:通过io_context::strand确保多个异步操作的处理函数在同一“执行链”中串行执行,避免数据竞争,无需显式使用互斥锁(std::mutex)。- 自定义执行器:支持C++20
std::execution标准,可集成第三方执行器(如线程池库),进一步扩展调度能力。
为什么选择Asio?
在C++异步编程领域,存在多种解决方案(如libuv、Poco库、Qt Network),但Asio凭借其独特优势,成为众多开发者的首选:
1. 极致的性能效率
Asio直接封装操作系统底层的高效I/O机制(epoll、IOCP、kqueue),避免了中间层的性能损耗。其核心优势体现在:
- 无线程开销:单线程可处理数千甚至数万并发连接,无需为每个连接创建线程,减少线程栈内存占用(通常每个线程栈大小为1-8MB)和上下文切换开销(每次切换约消耗1-10微秒)。
- 低延迟:基于事件驱动模型,I/O操作完成后立即触发处理,无需等待线程唤醒,延迟通常可控制在毫秒甚至微秒级。
- 高吞吐量:通过“批量事件处理”优化,减少系统调用次数(如epoll_wait一次可获取多个就绪事件),提升单位时间内的I/O处理能力。
例如,在Linux平台上,一个基于Asio的TCP服务器(单线程)可轻松处理10万级并发连接,且CPU利用率保持在较低水平(相比多线程模型,CPU占用可降低50%以上)。
2. 优雅的现代C++接口
Asio的接口设计严格遵循现代C++(C++11及以上)的风格和原则,提供了类型安全、可扩展的编程体验:
- 类型安全:通过强类型枚举(如
ip::tcp、ip::udp)、模板类(如basic_socket)避免隐式类型转换错误,编译期即可捕获大部分使用错误。 - 泛型编程:支持函数对象、lambda表达式、函数指针等多种回调形式,兼容
std::bind和C++20协程,代码灵活性高。 - 资源管理:所有I/O对象(如
socket、timer)均采用RAII(资源获取即初始化)模式,自动管理文件描述符、句柄等系统资源,避免内存泄漏和资源泄漏。 - 标准库集成:与C++标准库(如
std::string、std::vector、std::chrono)无缝集成,同时兼容Boost库生态(如Boost.SmartPtr、Boost.Utility),降低学习和迁移成本。
3. 成熟稳定的工业级质量
Asio自2003年发布以来,经过近20年的迭代和工业实践检验,其稳定性和可靠性已得到广泛认可:
- 活跃的社区支持:作为Boost库的核心组件,Asio拥有庞大的开发者社区,官方文档(Boost.Asio Documentation)完善,且有大量开源项目(如WebSocket++、cpp-netlib)基于其构建。
- 严格的测试:Asio的代码经过严格的单元测试、集成测试和跨平台测试,覆盖了各种异常场景(如网络中断、资源耗尽、信号中断),确保在生产环境中的稳定性。
- 长期维护:Christopher M. Kohlhoff仍主导Asio的开发,且定期发布更新,跟进C++标准的发展(如C++20协程、C++23网络库),保证库的前瞻性。
4. 灵活的使用场景
Asio的设计不局限于特定领域,可广泛应用于各种I/O密集型和并发密集型场景:
- 网络服务端:Web服务器、API网关、即时通讯服务器(IM)、游戏服务器、物联网(IoT)网关等。
- 网络客户端:高性能爬虫、分布式系统中的节点通信、实时数据采集工具等。
- 本地I/O应用:串口通信工具、定时任务调度器、日志收集系统等。
- 嵌入式开发:嵌入式Linux平台上的网络应用(如路由器、智能设备),因资源受限,更需要高效的异步模型。
例如,知名开源项目NGINX的C++端口NGINX++、WebSocket库WebSocket++、分布式计算框架Apache Arrow等均采用Asio作为底层I/O引擎。
Asio的两种版本
Asio提供两种分发版本,两者在API设计和核心功能上完全一致,但依赖关系和集成方式不同,开发者可根据项目需求选择:
| 特性 | Boost.Asio(Boost集成版) | Standalone Asio(独立版) |
|---|---|---|
| 依赖关系 | 依赖Boost库的其他组件(如Boost.System、Boost.Date_Time) | 无外部依赖(仅需C++11及以上标准库) |
| 获取方式 | 随Boost库一起安装(如libboost-all-dev) | 单独下载(Asio官网)或通过包管理器(如vcpkg) |
| 编译方式 | 需链接Boost相关库(如-lboost_system) | 无需链接额外库(头文件+少量源文件) |
| 适用场景 | 项目已依赖Boost库,或需要使用Boost生态的其他组件 | 项目不希望引入Boost依赖,或需要轻量级集成 |
| 版本更新 | 与Boost库版本同步(每3个月发布一次) | 独立更新,更新频率更高(通常每月有小更新) |
| 许可证 | Boost Software License(开源、商业友好) | Boost Software License(与Boost一致) |
版本选择建议
- 选择Boost.Asio:如果你的项目已经使用Boost库(如Boost.SmartPtr、Boost.Serialization),或需要使用Boost.Asio特有的扩展功能(如Boost.SSL集成),建议直接使用Boost.Asio,避免重复依赖。
- 选择Standalone Asio:如果你的项目追求轻量级,或不希望引入Boost的庞大依赖(Boost库完整安装后约占数百MB磁盘空间),建议使用Standalone Asio。独立版仅需包含头文件和一个源文件(
asio.cpp),即可集成到项目中。
需要注意的是,两种版本的API完全兼容,开发者可在项目后期根据需求无缝切换(如从独立版迁移到Boost版,只需修改头文件包含路径和链接选项)。
基本编程模型
Asio的核心设计基于“反应器模式”(Reactor Pattern),这是一种事件驱动的并发编程模式,其核心思想是“将I/O操作的触发和处理分离”——由操作系统监听I/O事件(如“socket可读”“定时器超时”),当事件发生时,通知应用程序执行对应的处理逻辑。Asio的基本编程流程可概括为以下5个步骤:
步骤1:创建I/O上下文(io_context)
io_context是Asio的核心组件,相当于“事件调度器”,负责管理I/O事件的注册、监听和分发。所有Asio的I/O对象(如socket、timer)都必须与io_context关联,才能进行异步操作。
创建io_context的代码非常简单:
#include<asio.hpp>intmain(){// 创建I/O上下文对象 asio::io_context io;// 后续步骤:创建I/O对象、启动异步操作...return0;}io_context的核心作用是维护一个“事件队列”,当异步操作完成时,对应的“完成事件”会被加入队列;io_context::run()方法则会循环处理队列中的事件,调用对应的处理函数,直到队列为空且没有未完成的异步操作。
步骤2:创建I/O对象并关联io_context
I/O对象是Asio中与具体I/O资源交互的载体,如steady_timer(定时器)、ip::tcp::socket(TCP客户端)、ip::tcp::acceptor(TCP服务器)等。所有I/O对象的构造函数都需要传入io_context对象,以建立关联。
例如,创建一个定时器对象:
// 创建定时器,关联io_context,设置5秒后超时 asio::steady_timer t(io, asio::chrono::seconds(5));再如,创建一个TCP客户端Socket:
// 创建TCP Socket,关联io_context asio::ip::tcp::socket sock(io);I/O对象的生命周期与io_context绑定——当io_context被销毁时,所有关联的I/O对象也会自动释放资源(如关闭Socket、取消定时器)。
步骤3:启动异步操作并指定完成处理程序
Asio的所有I/O操作都提供“异步版本”(方法名以async_开头),如async_wait(定时器异步等待)、async_connect(Socket异步连接)、async_read(异步读取数据)等。启动异步操作时,需要传入一个“完成处理程序”(Completion Handler)——这是一个函数对象(如lambda、函数指针、std::function),当异步操作完成(成功或失败)时,io_context会调用该处理程序。
完成处理程序的签名由具体的异步操作定义,通常第一个参数是asio::error_code类型,用于表示操作的结果(error_code::value() == 0表示成功,否则表示失败);后续参数根据操作类型而定(如async_read的处理程序会包含“读取的字节数”)。
例如,为定时器启动异步等待,并指定lambda作为完成处理程序:
// 启动异步等待,当定时器超时时调用lambda t.async_wait([](const asio::error_code& ec){if(!ec){// 检查操作是否成功(无错误) std::cout <<"Timer expired! Hello, Asio!"<< std::endl;}else{ std::cout <<"Timer error: "<< ec.message()<< std::endl;}});步骤4:运行io_context的事件循环
io_context::run()方法是Asio事件循环的入口,它会阻塞当前线程,不断从“事件队列”中取出完成事件,并调用对应的完成处理程序,直到满足以下两个条件之一才会返回:
- 所有异步操作已完成(无未处理的事件,且无正在等待的I/O操作);
- 调用
io_context::stop()或io_context::restart()方法主动终止事件循环。
在之前的定时器示例中,启动异步操作后,必须调用io.run()才能触发事件循环:
// 运行事件循环,处理异步事件 io.run();需要注意的是,io_context::run()是“阻塞式”的——如果没有启动任何异步操作,run()会立即返回(因为事件队列为空);如果有正在等待的异步操作(如定时器未超时、Socket未连接),run()会阻塞线程,直到这些操作完成并处理完所有事件。
此外,io_context支持多线程并发调用run()——当多个线程同时调用run()时,io_context会将事件分发到不同线程中执行,实现“线程池”模式。但需注意,默认情况下,同一个异步操作的完成处理程序可能在不同线程中执行,若处理程序操作共享数据,需通过strand(执行链)确保串行执行,避免数据竞争。
步骤5:处理异步操作结果
当异步操作完成后,io_context会调用对应的完成处理程序,并通过asio::error_code参数传递操作结果。开发者需要在处理程序中检查错误状态,并执行相应的逻辑(如重试操作、释放资源、终止程序等)。
常见的错误场景包括:
- 定时器被取消(
ec == asio::error::operation_aborted); - Socket连接失败(
ec == asio::error::connection_refused); - 读取数据时连接被关闭(
ec == asio::error::eof); - 系统资源不足(
ec == asio::error::resource_unavailable_try_again)。
例如,在TCP客户端连接的处理程序中处理错误:
// 异步连接到服务器 sock.async_connect(endpoint,[&sock](const asio::error_code& ec){if(!ec){ std::cout <<"Connected to server successfully!"<< std::endl;// 连接成功,开始异步读取数据char buf[1024]; sock.async_read_some(asio::buffer(buf),[&sock, buf](const asio::error_code& read_ec, std::size_t bytes_read){if(!read_ec){ std::cout <<"Received data: "<< std::string(buf, bytes_read)<< std::endl;}elseif(read_ec == asio::error::eof){ std::cout <<"Connection closed by server."<< std::endl;}else{ std::cout <<"Read error: "<< read_ec.message()<< std::endl;}});}else{ std::cout <<"Connect failed: "<< ec.message()<< std::endl;// 连接失败,可重试或退出}});进阶示例:TCP回声服务器
为了更直观地理解Asio的编程模型,下面实现一个简单的TCP回声服务器——服务器监听指定端口,接收客户端连接后,将客户端发送的数据原封不动地回传(即“回声”功能)。该示例将展示io_context、ip::tcp::acceptor(服务器监听)、ip::tcp::socket(客户端连接)的协同工作,以及异步操作的链式调用。
完整代码
#include<iostream>#include<memory>#include<asio.hpp>using asio::ip::tcp;// 会话类:处理单个客户端连接的读写操作classSession:public std::enable_shared_from_this<Session>{public:// 构造函数:接收客户端SocketSession(tcp::socket socket):socket_(std::move(socket)){}// 启动会话:开始异步读取客户端数据voidstart(){do_read();}private:// 异步读取数据(循环调用,直到连接关闭)voiddo_read(){autoself(shared_from_this());// 延长生命周期,避免处理程序执行时对象已销毁 socket_.async_read_some(asio::buffer(data_, max_length),[this, self](const asio::error_code& ec, std::size_t bytes_read){if(!ec){// 读取成功,调用do_write回传数据do_write(bytes_read);}elseif(ec == asio::error::eof){ std::cout <<"Client disconnected: "<< socket_.remote_endpoint().address()<< std::endl;}else{ std::cerr <<"Read error: "<< ec.message()<< std::endl;}});}// 异步写入数据(回传客户端发送的数据)voiddo_write(std::size_t length){autoself(shared_from_this()); asio::async_write(socket_, asio::buffer(data_, length),[this, self](const asio::error_code& ec, std::size_t /*bytes_written*/){if(!ec){// 写入成功,继续读取下一批数据do_read();}else{ std::cerr <<"Write error: "<< ec.message()<< std::endl;}});} tcp::socket socket_;// 与客户端通信的Socketenum{ max_length =1024};// 缓冲区最大长度char data_[max_length];// 数据缓冲区};// 服务器类:监听端口并接受客户端连接classServer{public:// 构造函数:初始化监听地址和端口,创建acceptorServer(asio::io_context& io_context,short port):acceptor_(io_context, tcp::endpoint(tcp::v4(), port)){do_accept();// 开始接受客户端连接}private:// 异步接受客户端连接(循环调用,持续接受新连接)voiddo_accept(){// 异步等待新连接,接受后创建Session对象处理 acceptor_.async_accept([this](const asio::error_code& ec, tcp::socket socket){if(!ec){// 接受连接成功,创建Session并启动 std::cout <<"New client connected: "<< socket.remote_endpoint().address()<< std::endl; std::make_shared<Session>(std::move(socket))->start();}else{ std::cerr <<"Accept error: "<< ec.message()<< std::endl;}// 继续接受下一个连接do_accept();});} tcp::acceptor acceptor_;// 服务器监听 acceptor};intmain(int argc,char* argv[]){try{if(argc !=2){ std::cerr <<"Usage: tcp_echo_server <port>\n";return1;}// 创建io_context asio::io_context io_context;// 创建服务器,监听指定端口(如 ./tcp_echo_server 8080) Server server(io_context, std::atoi(argv[1])); std::cout <<"Echo server started on port "<< argv[1]<<", waiting for clients..."<< std::endl;// 运行事件循环 io_context.run();}catch(std::exception& e){ std::cerr <<"Exception: "<< e.what()<<"\n";}return0;}代码解析
- Session类:
- 负责处理单个客户端的生命周期,使用
std::enable_shared_from_this确保在异步处理程序执行期间,对象不会被提前销毁(避免悬空指针)。 do_read():异步读取客户端发送的数据,读取成功后调用do_write()回传数据;若发生错误(如客户端断开连接),则输出错误信息。do_write():异步将读取到的数据回传给客户端,写入成功后再次调用do_read(),形成“读取-写入-读取”的循环,持续处理客户端数据。
- 负责处理单个客户端的生命周期,使用
- Server类:
tcp::acceptor:用于监听指定端口的TCP连接请求,构造时绑定到IPv4地址和指定端口(如8080)。do_accept():异步接受客户端连接,接受成功后创建Session对象并调用start()启动会话;无论是否成功,都会再次调用do_accept(),确保服务器持续接受新连接。
- main函数:
- 解析命令行参数(端口号),创建
io_context和Server对象。 - 调用
io_context.run()启动事件循环,服务器开始监听并处理客户端连接。
- 解析命令行参数(端口号),创建
运行方式
测试客户端:使用telnet或nc(netcat)工具连接服务器,发送数据后会收到回声:
# 客户端终端1 telnet localhost 8080 Trying 127.0.0.1... Connected to localhost. Hello Asio!# 输入数据 Hello Asio!# 收到服务器回传的回声# 客户端终端2(支持多并发连接)nc localhost 8080 Test Echo Server Test Echo Server 启动服务器:
./tcp_echo_server 8080服务器会输出:Echo server started on port 8080, waiting for clients...
编译:需链接Asio相关库(以Standalone Asio为例,编译命令如下):
g++ -std=c++11 tcp_echo_server.cpp -o tcp_echo_server -lasio 若使用Boost.Asio,需链接Boost.System库:
g++ -std=c++11 tcp_echo_server.cpp -o tcp_echo_server -lboost_system -pthread 服务器终端会输出客户端连接信息:
New client connected: 127.0.0.1 New client connected: 127.0.0.1 Client disconnected: 127.0.0.1 # 当客户端断开连接时 安装和配置(补充细节)
使用Boost.Asio
1. 源码安装(适用于需要自定义编译选项的场景)
- 下载Boost源码:从Boost官网下载最新版本(如Boost 1.85.0),解压到本地目录(如
/usr/local/src/boost_1_85_0)。
环境变量配置:
# 添加Boost库路径到LD_LIBRARY_PATH(临时生效)exportLD_LIBRARY_PATH=/usr/local/boost/lib:$LD_LIBRARY_PATH# 永久生效(添加到~/.bashrc或/etc/profile)echo'export LD_LIBRARY_PATH=/usr/local/boost/lib:$LD_LIBRARY_PATH'>> ~/.bashrc source ~/.bashrc 编译安装:
# 进入源码目录cd /usr/local/src/boost_1_85_0 # 运行bootstrap脚本生成b2构建工具(Linux/macOS) ./bootstrap.sh --prefix=/usr/local/boost # 指定安装路径# 编译并安装(--with-system表示仅安装system组件,Asio依赖该组件;-j4表示使用4线程编译) ./b2 --with-system -j4 install2. 在CMake项目中精细配置
若项目仅需Boost.Asio,无需链接整个Boost库,可在CMakeLists.txt中指定具体依赖:
cmake_minimum_required(VERSION 3.10) project(tcp_echo_server) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Boost库,仅需system组件(Asio依赖) find_package(Boost 1.70 REQUIRED COMPONENTS system) # 添加可执行文件 add_executable(tcp_echo_server tcp_echo_server.cpp) # 链接Boost.System库 target_link_libraries(tcp_echo_server Boost::system pthread # Linux下需链接pthread库(Boost.Asio依赖线程支持) ) # 指定Boost头文件路径(若Boost安装在非标准路径) if (Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) endif() 使用独立Asio
1. 源码集成(适用于轻量级项目)
- 下载独立Asio:从Asio官网下载最新版本(如asio-1.28.1),解压后得到
asio-1.28.1目录,其中include/asio为头文件目录,src/asio.cpp为唯一需要编译的源文件。 - 项目集成:
- 将
include/asio目录复制到项目的include目录下。 - 将
src/asio.cpp复制到项目的src目录下。
- 将
编译时包含头文件路径,并将asio.cpp一起编译:
g++ -std=c++11 src/main.cpp src/asio.cpp -o my_app -Iinclude -pthread 2. 在CMake项目中配置
独立Asio可通过find_package或直接集成源码,以下是两种常见配置方式:
方式1:通过Vcpkg安装后配置
cmake_minimum_required(VERSION 3.10) project(my_asio_project) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 查找Vcpkg安装的Asio find_package(asio REQUIRED) # 添加可执行文件 add_executable(my_app main.cpp) # 链接Asio库(独立版Asio通常为头文件库,仅需链接依赖的系统库) target_link_libraries(my_app asio::asio pthread # Linux下需链接pthread ) 方式2:直接集成源码(无需安装)
cmake_minimum_required(VERSION 3.10) project(my_asio_project) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 添加Asio头文件路径(假设asio目录在项目根目录下) include_directories(${PROJECT_SOURCE_DIR}/asio/include) # 添加Asio源文件(仅需编译asio.cpp) add_library(asio STATIC ${PROJECT_SOURCE_DIR}/asio/src/asio.cpp) # 添加可执行文件 add_executable(my_app main.cpp) # 链接Asio静态库和系统库 target_link_libraries(my_app asio pthread )