简介
- asio即异步输入输出;
- 一个跨平台的C++库,可移植;
- 采用前摄器模式Proactor,支持以同步或异步的方式处理事件,不需要使用多线程和锁,有效避免多线程编程带来的诸多副作用(如竞争,死锁等);
- asio官方文档;
Asio基本工作流程
同步操作
- 同步模式下,流程一步一步执行,需要上一步操作完成返回再执行下一步;
- 你的程序Your Program通过调用I/O对象来进行操作;
- I/O对象将操作请求发给I/O执行上下文;
- I/O执行上下文调用操作系统接口来执行操作;
- 操作系统将操作的结果返回给I/O执行上下文;
- I/O执行上下文将操作结果转发给I/O对象;
- I/O对象将执行结果发送给你的程序;
异步操作
- 异步模式下,由io_service提交io异步执行,程序不用等待io返回直接执行下一步;
- 异步执行由io_service的run()函数负责检测io返回并通知预先注册的回调句柄(即回调函数),由回调句柄执行io返回的后续流程;
- 你的程序Your Program通过调用I/O对象来进行操作;
- I/O对象将请求转发给I/O执行上下文;
- I/O执行上下文向操作系统发出操作信号,进行异步处理,同时你的程序可以做其他事;
- 操作系统将异步处理结果通知到I/O执行上下文;
- 你的程序调用io_context::run()(或类似的io_context成员函数)检索结果;当有未完成的异步操作时,调用io_context::run()会阻塞,所以通常会在开始第一个异步操作时调用它;
- 在调用io_context::run()时,I/O执行上下文会将操作结果从队列中取出,然后将其传递给你的结果处理接口;
前摄器模式Proactor
- 由使用者(Initiator)发起一个异步操作(Asynchronous Operation),同时创建一个异步回调对象(Completion Handler);
- 该异步操作交给了异步操作执行器(Asynchronous Operation Processor),由它负责执行异步操作,并在完成后将一个完成事件插入完成事件队列(Completion Event Queue);
- 前摄器(Proactor)驱动异步事件分派器(Asynchronous Event Demultiplexer)从完成事件队列中获取完成的事件(这是一个阻塞的过程),如果获取到则前摄器找出与该事件关联的回调对象并执行回调,继续后续流程;
使用条件
- asio位于命令空间 boost::asio,使用时需要包含头文件
#include "boost/asio.hpp"
;
常用类和函数
boost::asio::io_service
- I/O 服务,负责与操作系统交互,等待异步操作的结束并执行回调;
boost::asio::io_service service;
service.post(handler); // 优先将任务排进处理队列然后返回,任务会在某个时机被完成,即handler稍后会在某个调用了service.run()的线程中被调用
service.dispatch(handler); // 即时请求io_service去调用指定的任务
service.wrap(handler); // 当被调用时它会调用service.dispatch(handler)
service.run(); // 监听io事件响应并执行回调
boost::asio::io_context
- io对象,只有调用run方法的线程才会被asio调度去执行任务;
- 可以看作事件循环, socket 、timer都需要它;
boost::asio::io_context::run() // 运行事件循环
boost::asio::ip
- 网络通信部分
ip地址
boost::asio::ip::address(v4_or_v6_address) //把一个v4或者v6的地址转换成ip::address
boost::asio::ip::address:from_string(str) //根据一个IPv4地址(用.隔开的)或者一个IPv6地址(十六进制表示)创建一个地址
boost::asio::ip::address::to_string() // 返回ip地址的字符串。
boost::asio::ip::address_v4::broadcast([addr, mask]) // 创建了一个广播地址
boost::asio::ip::address_v4::any() // 返回一个能表示任意地址的地址。
boost::asio::ip::address_v4::loopback() // 返回环路地址(为v4/v6协议)
boost::asio::ip::host_name() // 用string数据类型返回当前的主机名
boost::asio::ip::address addr = boost::asio::ip::address::from_string("127.0.0.1");
boost::asio::ip::address addr = boost::asio::ip::address::from_string("www.baidu.com");
端点 endpoint
- 表示使用某个端口连接到的一个地址;
- 不同类型的socket有自己的endpoint类,如ip::tcp::endpoint、ip::udp::endpoint和ip::icmp::endpoint;
endpoint() // 默认构造函数
endpoint(protocol, port) // 创建可以接受新连接的服务器端socket
endpoint(addr, port) // 创建一个连接到某个地址和端口的端点
ocal_endpoint() // 返回套接字本地连接的地址
remote_endpoint() // 返回套接字连接到的远程地址
boost::asio::ip::tcp::endpoint ep1(ip::tcp::v4(), 8000);
boost::asio::ip::tcp::endpoint ep2( ip::address::from_string("127.0.0.1"), 8000);
套接字
- asio有三种类型的套接字:ip::tcp、 ip::udp、ip::icmp,对应需要包含头文件boost/asio/ip/tcp.hpp、boost/asio/ip/udp.hpp、boost/asio/ip/icmp.hpp;
基础函数
// 分配了一个原生的socket给这个socket实例
assign(protocol,socket);
// 用给定的IP协议(v4或者v6)打开一个socket
open(protocol);
// 绑定到一个端口地址
bind(endpoint);
// 用同步的方式连接到一个端口地址
connect(endpoint);
// 用异步的方式连接到一个端口地址
async_connect(endpoint);
async_connect(endpoint, connect_handler); // connect_handler用来处理接收连接成功消息
// 套接字是否打开
is_open();
// 关闭套接字, 任何的异步操作都会被立即关闭
close();
// 关闭套接字, 立即使send或者receive操作失效
shutdown(type_of_shutdown);
// 取消套接字上所有的异步操作
cancel();
// 示例
boost::asio::ip::tcp::endpoint ep( boost::asio::ip::address::from_string("127.0.0.1"), 8000); // 创建端点
boost::asio::io_service service; // 创建io服务
boost::asio::ip::tcp::socket sock(service); // 创建套接字实例
sock.open(boost::asio::ip::tcp::v4()); //用ipv4方式打开套接字
sock.connect(ep); //同步连接端点
sock.shutdown(ip::tcp::socket::shutdown_receive); //终止
sock.close(); //关闭
读写函数
async_receive(buffer, [flags,] handler); // 启动从套接字异步接收数据的操作
async_read_some(buffer,handler); // 接收一次数据, 收到多少是多少
async_read_until(stream, stream_buffer, delim, handler); // 启动一个异步read操作, 在读取到某个分隔符时结束
async_read_until(strem, stream_buffer, completion, handler); // 启动一个异步read操作, 由一个完成处理方法判断是否结束
async_receive_from(buffer, endpoint[, flags], handler); // 启动从一个指定端点异步接收数据的操作
async_send(buffer [, flags], handler); // 启动一个异步发送缓冲区数据的操作
async_write_some(buffer, handler); // 同async_send,发送一次数据, 需要发的数据未必一次就可以发完
async_send_to(buffer, endpoint, handler); // 启动一个异步发送缓冲区数据到指定端点的操作
receive(buffer [, flags]); // 同步的从所给的缓冲区读取数据;在读完所有数据或者错误出现之前,这个函数都是阻塞的
receive_from(buffer, endpoint [, flags]); //同步的从一个指定的端点获取数据并写入到给定的缓冲区;在读完所有数据或者错误出现之前,这个函数都是阻塞的
read_some(buffer); // 同 receive(buffer)
read_until(stream, stream_buffer, delim); // 启动一个同步read操作, 在读取到某个分隔符时结束
read_until(stream, stream_buffer, completion); // 启动一个同步read操作, 由一个完成处理方法判断是否结束
send(buffer [, flags]); // 同步的发送缓冲区的数据;在所有数据发送成功或者出现错误之前,这个函数都是阻塞的
send_to(buffer, endpoint [, flags]); // 同步的把缓冲区数据发送到一个指定的端点;在所有数据发送成功或者出现错误之前,这个函数都是阻塞的
write_some(buffer); // 同 send(buffer)
available(); // 返回有多少字节的数据可以无阻塞地进行同步读取
// 示例
boost::asio::ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 8000);
boost::asio::io_service service; // 创建io服务
boost::asio::ip::tcp::socket sock(service);
sock.connect(ep);
sock.write_some(buffer("123456"));
std::cout << "size=" << sock.avaiable() << std::endl;
char buff[32];
size_t read = sock.read_some(buffer(buff));
设置查询函数
get_io_service(); // 返回构造函数中传入的io_service实例
get_option(option); // 返回套接字的属性
set_option(option); // 设置套接字的属性
io_control(cmd); // 在套接字上执行一个I/O操作
接收器 acceptor
- 对应socket API的accept()函数功能,用于服务器端,在指定的端口号接受连接,必须配合socket类才能完成通信;
boost::asio::ip::tcp::acceptor acceptor; // 创建一个tcp接收器
acceptor.async_accept(socket, handle_accept); // 接收连接
解析器resolver
- 对应socket API的getaddrinfo()系列函数,用于客户端解析网址获得可用的IP地址,解析得到的IP地址可以使用socket对象连接;
boost::asio::error
- 这个命名空间包含了调用I/O对象时返回的错误码
知识总结,交流学习,不当之处敬请指正,谢谢!