INTERACTIVE LAB

cppVIP本机实验0 次浏览 更新于 2026-09-29

Boost.Asio 库使用详解

学习 Boost.Asio 的网络编程层次、核心类型与异步通信方法。

需在本地环境完成,站点沙箱无法直接运行。

前言

由于C/C++一直以来没有推出标准的网络库,导致每次我们在网络编程中,就不得直接调用系统API来进行编程,但很多步骤都是重复不变的的,却又不得不写,非常繁琐。

但其实作为C/C++准标准库的boost库,早就有了一个网络库,名为asio,也许在下一个C++标准,就加入了标准库也说不一定。

如果你没有安装boost库,那么可以直接去官方下载:Boost,官方已经推出了编译好的版本、下载相应的window安装程序即可:

image.png

除此之外,我还写了一篇基于asio库实现的聊天室:手写一个聊天室(单聊、群聊、文件传输)。

该项目的服务器因为使用的asio库,所以完全跨平台,可以直接在windows、linux平台进行编译。

注意,本文基于1.88版本,版本不同可能存在差异。

理清层次

既然是网络编程,那么就必然少不了TCP与UDP的身影,虽然这个网络模块还可以控制的更加深入,也支持其它协议,但这里就不更多讲解了。

不过这个库也有很不友好的地方,那就是层次太多了!所以我们首先来理一下各个类的层次关系。

比如首先,boost这个库有很多模块,asio就是其中的一个网络模块,这些所有模块都是在boost这个命名空间下:

using namespace boost;

然后我们这里是使用asio这个网络模块里面的各个类,所以就是:

using namespace boost::asio;

而asio空间中,我们首先不可避免的就是io_context。

这个类非常重要,它相当于我们程序与系统之间I/O操作的中介,我们所有的接受或发送数据操作,都是通过将需求提交给这个类,然后这个类再交给计算机来执行的。

基于这个理念,基本所有asio网络库中有读写I/O需求的类,其构造函数的第一个参数就是它,比如后面要讲的收发数据的socket类,以及tcp服务器用于接受用户连接的acceptor类等

而这个io_context就在asio里面,所以在using namespace boost::asio;之后,就可以直接用它实例化对象:

io_context io;

除了io_context 外,asio里面还有一个函数非常重要,那就是buffer函数,它的作用其实就是构造一个结构体,大致如下:

struct{
void* buf;
s_size len;
}

该网络模块中所有的收发数据操作,都不接受单独的字符串,而是这样一个结构体,分别为缓存区的首地址以及缓存区的大小。

总结一下就是,asio里面,直接用到的就是一个类:io_context 与一个函数:buffer。

然后继续深入,紧接着就是asio里面进一步的命名空间ip,我们的TCP和UDP相关类,就在这个ip里面。

比如我们想使用tcp,其socket类,就是:ip::tcp::socket,而udp的socket类就是:ip::udp::socket。

由于我们通常程序用中可能只使用其中某一个协议,比如只使用TCP,那就可以这样写:

using asio::ip::tcp;

作为TCP服务器,用于接受客户端连接的类acceptor也在其中。

这样就不用每次都加前面那一大长串了(如果tcp与udp都会使用,那就别这样写了,会混淆)。

除了socket类,我们在网络通信中还需要对方的ip与端口才行,这就用到了类endpoint,它同样在tcp与udp中都有。

还有就是地址处理类:address,直接就在ip里面,其最常用的就是它的静态函数from_string,将十进制的ip地址转化为网络字节序。

最后总体总结一下常用的类所在位置:

空间 类或函数
boost::asio io_context,buffer
boost::asio::ip address
boost::asio::ip::tcp socket,acceptor,endpoint
boost::asio::ip::udp socket,endpoint

TCP编程实例

这个网络库不仅支持同步,而且还支持异步,所以下面我们分别进行讲解。

同步实例

服务器:

#include<iostream>
#include"boost/asio.hpp"
using namespace std;
using namespace boost;
using asio::ip::tcp;

int main() {
	cout << "server start ……" << endl;
	asio::io_context io;
	tcp::acceptor acptr(io, tcp::endpoint(tcp::v4(), 6688));

	tcp::socket sock(io);
	acptr.accept(sock);
	cout << "client:" << sock.remote_endpoint().address() << endl;
	try {
		while (true) {
			char buf[0xFF];
			sock.receive(asio::buffer(buf));
			sock.send(asio::buffer(buf));
		}
	}
	catch (std::exception& e) {
		cout << e.what();
	}

	sock.close();
	::system("pause");
}

这里写的是只接受一个客户端连接的回声服务器,可以看到,这里用到的acceptor 与socket ,第一个参数都为这个io_context

注意一下逻辑的转化,比如以前我们使用纯系统网络api时,是必须要先有一个监听socket,但使用了asio就有点不一样了,acceptor 类就封装了一个监听socket,通过其构造参数的第二个,endpoint,来确定监听地址与端口。

tcp::acceptor acptr(io, tcp::endpoint(tcp::v4(), 6688));
该实验为 VIP 专享内容,
请开通后继续阅读后续 70% 并运行完整示例~

DISCUSSION

评论 0

还没有评论,来留下第一条吧。