5、boost库使用asio | 您所在的位置:网站首页 › polling模式 › 5、boost库使用asio |
asio库基于操作系统提供的异步机制,采用前摄器模式(Proactor)实现可移植的异步(或同步)IO操作,不需要使用多线程和锁,有效避免多线程编程带来的诸多有害副作用(如竞争,死锁)。
asio封装了操作系统的select、kqueue、poll/epoll、overlapped I/O等机制,实现异步IO模型。在同步模式下,程序发起一个IO操作,向io_service提交请求,io_service把操作转交给操作系统,同步地等待。当IO操作完成时,操作系统通知io_service,然后io_service再把结果发回给程序,完成整个同步流程。在异步模式下,程序除了要发起IO操作,还要定义一个用于回调的完成处理函数。io_service同样把IO操作转交给操作系统执行,但它不同步等待,而是立即返回。调用io_service的run()成员函数可以等待异步操作完成,当异步操作完成时io_service从操作系统获取结果,在调用handler执行后续逻辑。 1. handler 回调函数形式: void handler(const error_code &ec); void handler(const error_code &ec, std::size_type bytes_transferred); 2. io_serviceio_service类代表了系统里的异步处理机制(如epoll),必须在asio库里的其他对象之前初始化,其他对象则向io_service提交异步操作handler。 3. const_buffer数据缓冲区,保存了一个void*的内存地址和数据长度。 4. 网络通信相关asio支持TCP、UDP和ICMP通信协议,很好的封装了伯克利socket api。其中TCP部分定义了一些用于TCP通信的typedef类型,包括端点类endpoint、套接字类socket、流类iostream,以及接收器acceptor、解析器resolver等。 class tcp { public: /// The type of a TCP endpoint. typedef basic_endpoint endpoint; /// The TCP socket type. typedef basic_stream_socket socket; /// The TCP acceptor type. typedef basic_socket_acceptor acceptor; /// The TCP resolver type. typedef basic_resolver resolver; /// The TCP iostream type. typedef basic_socket_iostream iostream; /// ...... };endpoint包含IP地址和通信用的端口号。 socket可以在构造时指定使用的协议或者endpoint,或者稍后调用成员函数connect()。连接成功后可以用local_endpoint()和remote_endpoint()获得连接两端的端点信息,用available()获取可读取的字节数,用receive()/read_some()和send()/write_some()读写数据,当操作完成后使用close()函数关闭socket。如果socket没有被关闭,则其析构时也会自动关闭。 acceptor对应Socket API的accept()函数,用于服务器端。acceptor可以像传统socket API一样使用,open()打开端口,bind()绑定再用listen()侦听端口,但更方便的是使用它的构造函数,传入endpoint直接完成这三个动作。 5、IO模型在asio框架中,同步和异步区别 (2)同步的io主要流程如下: 应用程序调用IO对象成员函数执行IO操作 IO对象向io_service 提出请求. io_service 调用操作系统的功能执行连接操作. 操作系统向io_service 返回执行结果. io_service将错误的操作结果翻译为boost::system::error_code类型,再传递给IO对象. 如果操作失败,IO对象抛出boost::system::system_error类型的异常. (1)而异步IO的处理流程则有些不同:
应用程序调用IO对象成员函数执行IO操作 IO对象请求io_service的服务 io_service 通知操作系统其需要开始一个异步连接. 操作系统指示连接操作完成, io_service从队列中获取操作结果 应用程序必须调用io_service::run()以便于接收结果 调用io_service::run()后,io_service返回一个操作结果,并将其翻译为error_code,传递到事件回调函数中 6、io_service对象 io_service的作用: io_servie 实现了一个任务队列,这里的任务就是void(void)的函数。Io_servie最常用的两个接口是post和run,post向任务队列中投递任务,run是执行队列中的任务,直到全部执行完毕,并且run可以被N个线程调用。Io_service是完全线程安全的队列。 io_service对象提供的接口有run、run_one、poll、poll_one、stop、reset、dispatch、post,最常用的是run、post、stop: post用于发布io事件,如timer,socket读写等,一般由asio框架相应对象调用,无需我们显式调用。 run用于监听io事件响应,并执行响应回调,对于异步io操作需要在代码中显式调用,对于同步io操作则由io对象隐式调用(并不是run函数,不过也是等待io事件)。可见,io_service提供的是一个生产者消费者模型。在异步io操作中需要我们手动控制消费者,调用run函数,它的基本工作模式如下: 等待io事件响应,如果所有io事件响应完成则退出 等待到io事件响应后,执行其对应的回调 继续等待下一个io事件,重复1-2 从中可以看出,io_service是一个工作队列的模型。在使用过程中一般有如下几个需要注意的地方: (1) run函数在io事件完成后会退出,导致后续基于该对象的异步io任务无法执行由于io_service并不会主动常见调度线程,需要我们手动分配,常见的方式是给其分配一个线程,然后执行run函数。但run函数在io事件完成后会退出,线程会终止,后续基于该对象的异步io任务无法得到调度。 解决这个问题的方法是通过一个asio::io_service::work对象来守护io_service。这样,即使所有io任务都执行完成,也不会退出,继续等待新的io任务。
|
CopyRight 2018-2019 实验室设备网 版权所有 |