asio库基于操作系统提供的异步机制,采用前摄器设计模式(Proactor)实现了可移植的异步(或者同步)IO操作,而且并不要求使用多线程和锁定,有些的避免了多线程编程带来的诸多有害副作用(如条件竞争、死锁等)。
目前asio主要关注网络通信方面,使用大量的类和函数封装了socket API,提供了一个现代C++风格的网络编程接口,支持TCP,ICMP,UDP等网络通信协议。但asio的异步操作并不局限于网络编程,他还支持串口读写,定时器,SSL等功能,而且asio是一个很好的富有弹性的框架,可以扩展到其他有异步操作需要的领域。

asio概述

asio库基于前摄模式(Proactor)封装了操作系统的select,poll/epoll,kqueue,overlapped I/O等机制,实现了异步IO模型。他的核心类是io_service,相当于前摄模式中的Proactor角色,asio的任何操作都需要有io_service的参与。
在同步模式下,程序发起一个IO操作,向io_service提交请求,io_service把操作转给操作系统,同步的等待。当IO操作完成时,操作系统通知io_service,然后io_service在把结果发回给程序,完成整个同步流程。这个处理流程与多线程join()等待方式很相似。
在异步模式下,程序除了要发起的IO操作,还要定义一个用于回调的完成处理函数。io_service同样把IO操作转交给操作系统执行,但它不同步等待,而是立即返回。调用io_service的run()成员函数可以等待异步操作完成,当异步操作完成时io_service从操作系统获取执行结果,调用完成处理函数。
asio不直接使用操作系统提供的线程,而且定义了一个自己的线程概念:strand,它保证在多线程的环境中代码可以正确的执行,而无需使用互斥量。io_serviec::strand::wrap()函数可以包装在一个函数在strand中执行。
IO操作会经常使用到缓冲区,asio库专门用两个类mutable_buffer和const_buffer来封装这个概念,他们可以被安全的应用在异步的读写操作中,使用自由函数buffer()能够包装常用的C++容器类型,如数组、arrary、vector、string等,用read(),write()函数来读取缓冲区。
asio是一个相当复杂的库,本书只涉及其中的基本概念,还有许多异步IO相关的概念,在此不一一介绍。

定时器

定时器是asio库里最简单的一个IO模型示范,提供等待时间终止的功能,通过它我们可以快速熟悉asio的基本使用方法。

#include <iostream>
#include <conio.h>
using namespace std;
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
using namespace boost;
using namespace boost::asio;
//同步定时器
void test1()
{
io_service ios;//所有的asio程序必须要有一个io_service对象
deadline_timer t(ios,boost::posix_time::seconds(2));//两秒钟后定时器终止
cout<<t.expires_at()<<endl;//查看终止的决定时间
t.wait();//调用wait()同步等待
cout<<"hello asio"<<endl;
//可以把它与thread库的sleep()函数对比研究一下,两种虽然都是等待,但内部机制完全不同:thread库的sleep()使用了互斥量和条件变量,在线程中等待,而asio则是调用了操作系统的异步机制,如select,epool等完成。
//同步定时器的用法很简单,但它演示了asio程序的基本结构和流程:一个asio程序首先要定义一个io_service对象,它是前摄器模式中最重的proactor角色,然后我们声明一个IO操作(这里是定时器),并把它挂接在io_service上,再然后就可以执行后续的 同步或异步操作。
}
//异步定时器:代码大致与同步定时器相同,增加了回调函数,并使用io_service_run()和定时器的async_wait()
//首先我们要定义回调函数,asio库要求回调函数只能有一个参数,而且这个参数必须是const asio::error_code&类型 void myprint(boost::system::error_code ec)
{
cout<<"hello asio"<<endl;
}
void test2()
{
io_service ios;
deadline_timer t(ios,boost::posix_time::seconds(3));
t.async_wait(myprint);//异步等待,传入回调函数,立即返回
cout<<"it show before t expired."<<endl;
ios.run();//很重要,异步IO必须
cout<<"runned"<<endl;//将与hello asio一起输出,说明run()是阻塞函数
//异步等待async_wait(),它通知io_service异步的执行IO操作,并且注册了回调哈思楠,用于在IO操作完成时有事件多路分离器分派返回值(error_code)调用。
//最后我们必须调用io_service的run()成员函数,它启动前摄器的事件处理循环,阻塞等待所有的操作完成并分派事件。如果不调用run()那么虽然被异步执行了,但没有一个等待他完成的机制,回调函数将得不到执行的机会。
}
//下面我们实现一个可以定时执行任意函数的定时器 a_timer(asyc timer),它持有一个asio定时器对象和一个计数器,还有一个function对象用来保存回调函数
class a_timer
{
private:
int count,cout_max; //计数器成员变量
function<void()> f; //function对象,持有无参数无返回的可调用物
deadline_timer t;//asio定时器
public:
//构造函数初始化成员变量,将计数器清理,设置计数器的上限,拷贝存储回调函数,并立即启动定时器
//之所以要"立即"启动,是因为我们必须包装在io_service.run()之前至少有一个异步操作在执行,否则io_service.run()会因为没有事件处理而立即不等待返回。
template<typename F>a_timer(io_service& ios,int x,F func):f(func),cout_max(x),count(0),t(ios,posix_time::microsec(500))//模板类型,可接受任意可调用物
{
t.async_wait(bind(&a_timer::call_func,this,placeholders::error));//命名空间下asio::placeholders的一个占位符error,他的作用类似于bind库的占位符_1,_2,用于传递errror_code值。
} //call_func()内部累加计数器,如果计数器未达到上限则调用function对象f,然后重新设置定时器的终止时间,再次异步等待被调用,从而达到反复执行的目的。
void call_func(const boost::system::error_code &)
{
if(count >= cout_max)
{
return;
}
++count;
f();
t.expires_at(t.expires_at()+posix_time::millisec(500));//设置定时器的终止时间为0.5秒之后
t.async_wait(bind(&a_timer::call_func,this,placeholders::error));
}
};
void print1(int index)
{
cout<<"hello asio:"<<index<<endl;
}
void print2()
{
cout<<"hello boost"<<endl;
}
void test3()
{
io_service ios;
a_timer a(ios,10,bind(print1,2));//启用第一个定时器
a_timer at(ios,5,print2);//启用第二个定时器
ios.run();//ios等待异步调用结束
}
//查询网络地址
/*之前关于TCP通信的所有论述我们都是使用直接的IP地址,但在实际生活中大多数时候我们不可能知道socket连接另一端的地址,而只有一个域名,这时候我们就需要使用resolver类来通过域名获得可用的IP,它可用实现与IP版本无关的网址解析。
resolver使用内部类query和iterator共同完成查询IP地址的工作:首先使用网址和服务器名创建query对象,然后由resolver()函数生产iterator对象,它代表了查询到的ip端点。之后就可以使用socket对象尝试连接,直到找到一个可用的为止。
*/
#include <boost/lexical_cast.hpp>
void resolv_connect(ip::tcp::socket &sock,const char* website ,int port)//使用此函数来封装resolver的调用过程
{
ip::tcp::resolver rlv(sock.get_io_service());//resolver对象
ip::tcp::resolver::query qry(website,lexical_cast<string>(port));//创建一个query对象;query只接受字符串参数 ip::tcp::resolver::iterator iter=rlv.resolve(qry);
ip::tcp::resolver::iterator end;//逾尾迭代器
system::error_code ec=error::host_not_found;
for (; ec && iter != end;++iter)
{
sock.close();
sock.connect(*iter,ec);//尝试连接端点
}
if (ec)//只有当ec为0时,才会连接成功
{
cout<<"can't connect."<<endl;
throw system::system_error(ec);
}
cout<<"connect success."<<endl;
}
void test4()
{
try
{
io_service ios;
ip::tcp::socket sock(ios);
resolv_connect(sock,"www.boost.org",80);
//其他操作
ios.run();
}
catch (std::exception& e)
{
cout<<e.what()<<endl;
}
}
void test(char t)
{
std::cout<<"press key====="<<t<<std::endl;
switch (t)
{
case '1':test1();break;
case '2':test2();break;
case '3':test3();break;
case '4':test4();break;
case 27:
case 'q':exit(0);break;
default: std::cout<<"default "<<t<<std::endl;break;
}
}
void main()
{
while(1)
test(getch());
}

[Boost基础]并发编程——asio网络库——定时器deadline_timer的更多相关文章

  1. [Boost基础]并发编程——asio网络库——同步socket处理

    网络通信简述 asio库支持TCP,UDP和ICMP通信协议,它在名字空间boost::asio::ip里提供了大量的网络通信方面的函数和类,很好的封装了原始的Berkeley Socket API, ...

  2. [Boost基础]并发编程——asio网络库——异步socket处理

    异步服务器端 #include <conio.h> #include <iostream> using namespace std; #include <boost/as ...

  3. python基础-并发编程02

    并发编程 子进程回收的两种方式 join()让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源 from multiprocessing import Process import ti ...

  4. python语法基础-并发编程-进程-进程理论和进程的开启

    ############################################## """ 并发编程的相关概念: 进程 1,运行中的程序,就是进程,程序是没有生 ...

  5. python语法基础-并发编程-进程-进程锁和进程间通信

    ###############   守护进程  ############## """ 守护进程 父进程中将一个子进程设置为守护进程,那么这个子进程会随着主进程的结束而结束 ...

  6. 陈硕 - Linux 多线程服务端编程 - muduo 网络库作者

    http://chenshuo.com/book/ Muduo网络库源码分析(一) EventLoop事件循环(Poller和Channel)http://blog.csdn.net/nk_test/ ...

  7. python基础-并发编程part01

    并发编程 操作系统发展史 穿孔卡片 读取数据速度特别慢,CPU利用率极低 单用户使用 批处理 读取数据速度特别慢,CPU利用率极低 联机使用 脱机批处理(现代操作系统的设计原理) 读取数据速度提高 C ...

  8. boost中asio网络库多线程并发处理实现,以及asio在多线程模型中线程的调度情况和线程安全。

    1.实现多线程方法: 其实就是多个线程同时调用io_service::run for (int i = 0; i != m_nThreads; ++i)        {            boo ...

  9. 网络编程基础----并发编程 ---守护进程----同步锁 lock-----IPC机制----生产者消费者模型

    1  守护进程: 主进程 创建 守护进程   辅助主进程的运行 设置进程的 daemon属性 p1.daemon=True 1 守护进程会在主进程代码执行结束后就终止: 2 守护进程内无法再开启子进程 ...

随机推荐

  1. 整合SSH三大框架用注解时报An AnnotationConfiguration instance is required to use

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 's ...

  2. 一个IP每天只弹一次广告窗口

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  3. windows desktop.ini

    win7桌面上的两个desktop.ini文件千万不要删除,win7系统里的desktop.ini文件是有用的. 详解 Desktop.ini 配置设置文件1 http://blog.sina.com ...

  4. CURL基础

    下载单个文件: #下载单个文件,默认将输出打印到标准输出中(STDOUT)中curl http://www.centos.org # 将文件下载到本地并命名为mygettext.html curl - ...

  5. PyconChina2015丁来强Pydata Ecosystem

    pydata ecosystem基于python的数据分析生态系统 0. Agenda Data Science ecosystem Data Wrangling Data Analysis Data ...

  6. Java字节码中的方法调用

    invokestatic,用于static修饰的方法.任何时候调用的时候只需要类名+方法名即可,无需new.JVM直接将其映射到方法区,执行速度极快.当该方法需要参数的时候,invokestatic会 ...

  7. Python函数式编程:Lambda表达式

    首先我们要明白在编程语言中,表达式和语句的区别. 表达式是一个由变量.常量.有返回值的函数加运算符组成的一个式子,该式子是有返回值的 ,如  a + 1 就是个表达式, 单独的一个常量.变量 或函数调 ...

  8. hdu3483之二项式展开+矩阵快速幂

    A Very Simple Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Ot ...

  9. 给刚通过51入门的新人讲讲S12(MCS12XS128)与51的差别

    MCS51是keil也对应地做好了非常多,也就是有非常多对你而言是透明的,是你不必关心的,你所要接触的寄存器数量也非常小,在这个时候你很多其它是写函数,仅仅只是针对这个平台写C程序比在PC上写C控制台 ...

  10. CentOS6.5+php5.3听云安装过程

    听云安装过程请参考听云安装指导页面:http://doc.tingyun.com/help/html/doc/server_novice.html 根据自己的服务器系统和语言包下载对应的 安装包 安装 ...