让风了还有别的wwW1000mt车库出入口退让吗,wlan的网络1000mtcom不支持是吗

LG电子为您提供各种各样的智能家用产品,LG智能家电产品让您的生活更轻松更舒适 | LG中国官网
To properly experience our LG.com website, you will need to use an alternate browser or upgrade to a newer version of Internet Explorer (IE9 or greater).
LG.com网站采用响应式网页设计来提供符合您设备屏幕大小的舒适体验。为了让您享受最好的体验,请按照以下说明进行调整。
如果您正在使用IE 8或者更早的版本,您将需要使用一个可替换浏览器,比如Firefox或者Chrome,也可以选择更新到新版IE(IE 9或者更高版本)。
如果您正在使用IE 9或者更高版本,请按照以下步骤关闭您IE浏览器的“兼容性视图设置”
右击浏览器顶部,确定“菜单栏”选项是勾选状态。
从菜单栏选择“工具”然后选择“兼容性视图设置”
在弹出的菜单中取消三个勾选框的选择然后点击“关闭”
您的浏览器窗口将会自动刷新,接下来就可以开
启您的LG之旅了.
LG.com不支持SSLv2,v3,IE 6浏览器需要更改TLS 1.0选项.
1)进入Internet选项
2)选择“高级”选项卡,勾选使用TLS 1.0
(或者使用TLS 1.1,1.2)
* 在更改选项后,如果您仍无法使用HTTPS访问
页面,请联系技术团队 或者第三方技术团队。
激发你的创造力
独注细微,精益求精
绝美影音旗舰发现无边框之美
LG V30 | LG V30+的无边框合计和18:9的完美平衡比例,让您一手掌控影音旗舰。除了惊艳的外形设计,织纹状保护面让其达到IP68防水防尘等级,甚至通过了美国军事规格掉落测试(MILSTD-810G)
Smart ThinQLG智慧家电APP
从一台,到一张
LG PRIME UHD TV
色彩是电视不可或缺的重要元素,它能细腻呈现画面所想表达的深层情感
LG 双o门中门(R)
LG 门中门(R) 让您最爱的食物触手可及。革新冰箱门设计,给您带来便捷生活体验。多次开门取放您最爱的食物,制冷效果依然表现出众。
重新定义洗衣机TWINWash 双擎
滚筒/波轮同步分类2合1洗衣机颠覆传统的洗涤方式分类洗涤 | 同步洗涤 | 节省空间 | 节省时间
蒸汽除菌 健康呵护
蒸汽除菌99.9&#37 ● 蒸汽柔顺 ● 蒸汽清新通过深层渗透衣物的蒸汽,去除细菌和异味,减少褶皱。给婴儿和家人更多健康呵护。
LG客服热线
个人顾客 :400-819-9999(全国热线中心)商用顾客 :400-819-0011(电视/显示器商用顾客)周一至周日:08:00 ~ 20:00
周一至周日:08:00 ~ 20:00友情提示:支持键盘左右键“← →”翻页
分享次数:
文章内容导航
第1页:初次接触MT后该了解的事儿
·······················
没有相关搜索结果!
热门游戏攻略推荐
最新下载推荐
近期游戏大作推荐
热点内容图文推荐
近期热点内容回顾
精彩视频推荐
Copyright& GamerSky.com All rights reserved. 游民星空 版权所有
冀ICP证B2-本田锋范1.5 MT一天内跑长途1000多公里有什么影响吗?跑的都是高速。时速在100-160之间。_百度知道
本田锋范1.5 MT一天内跑长途1000多公里有什么影响吗?跑的都是高速。时速在100-160之间。
中途只休息了一次,感觉现在车子的声音有点大。发动机震动比较明显。谢谢哪位好心帮我解决这个烦恼吧!
我有更好的答案
只要是纯正的本田机油 每3-5小时要休息30-60分钟 就OK 啦 最好不要连续作业 对车 对人都有好处
采纳率:24%
没关系 跑完了 去保养 速度 别太快就ok了
润滑油太差
换了润滑油就没事了吗?
为您推荐:
其他类似问题
您可能关注的内容
本田锋范的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。boost.ASIO-可能是下一代C++标准的网络库 - wlmbz - 博客园
posts - 17, comments - 3, trackbacks - 0, articles - 0
曾几何时,Boost中有一个Socket库,但后来没有了下文,C++社区一直在翘首盼望一个标准网络库的出现,网络上开源的网络库也有不少,例如Apache Portable Runtime就是比较著名的一个,也有像ACE这样重量级的网络框架。去年,Boost将ASIO纳入了自己的体系,由于Boost的影响力,ASIO有机会成为标准网络库。作者Chris Kohlhoff以ASIO为样本向C++标准委员会提交了一个网络库建议书,里面提到:ASIO的覆盖范围:? Networking using TCP and UDP, including support for multicast.? Client and server applications.? Scalability to handle many concurrent connections.? Protocol independence between IPv4 and IPv6.? Name resolution (i.e. DNS).? Timers.不在ASIO考虑范围之内的:? Protocol implementations such as HTTP, SMTP or FTP.? Encryption (e.g. SSL, TLS).? Operating system specific demultiplexing APIs.? Support for realtime environments.? QoS-enabled sockets.? Other TCP/IP protocols such as ICMP.? Functions and classes for enumerating network interfaces.Boost.Asio支持以下平台:? Win32 using Visual C++ 7.1 and Visual C++ 8.0.? Win32 using Borland C++Builder 6 patch 4.? Win32 using MinGW.? Win32 using Cygwin.? Linux (2.4 or 2.6 kernels) using g++ 3.3 or later.? Solaris using g++ 3.3 or later.? Mac OS X 10.4 using g++ 3.3 or later.? QNX Neutrino 6.3 using g++ 3.3 or later.? FreeBSD using g++ 3.3 or later.参考ACE的Proactor模式,ASIO采用异步通讯机制,同时参考了Symbian C++ sockets API、Microsoft .NET socket classes和Open Group的Extended Sockets API。
Asio 是一个跨平台的C++开发包用来处理网络和低级I/O编程,通过先进的C++方法为开发人员提供连续异步模型。示例代码:& void handle_read(const asio::error_code& error,&&&&& size_t bytes_transferred)& {&&& if (!error)&&& {&&&&& asio::async_write(socket_,&&&&&&&&& asio::buffer(data_, bytes_transferred),&&&&&&&&& make_custom_alloc_handler(allocator_,&&&&&&&&&&& boost::bind(&session::handle_write,&&&&&&&&&&&&& shared_from_this(),&&&&&&&&&&&&& asio::placeholders::error)));&&& }& }& void handle_write(const asio::error_code& error)& {&&& if (!error)&&& {&&&&& socket_.async_read_some(asio::buffer(data_),&&&&&&&&& make_custom_alloc_handler(allocator_,&&&&&&&&&&& boost::bind(&session::handle_read,&&&&&&&&&&&&& shared_from_this(),&&&&&&&&&&&&& asio::placeholders::error,&&&&&&&&&&&&& asio::placeholders::bytes_transferred)));&&& }& }
boost真是个好东西,每次去逛总会有惊喜。这次的惊喜是发现了asio,一个跨平台的支持异步I/O的网络通讯socket库。异步I/O是一种高效的I/O模型,在Windows平台下这种机制的代表就是IOCP完成端口模型。事实上,asio在Windows平台上的实现就是对IOCP的封装。其实在网络通讯这一块,已经有许多成熟的框架了,最典型的就是ACE,一个网络通讯设计模式的集大成者。但ACE对我来说太重型了,而且其起源于90年代,与标准库的集成不是太好,比如ACE就有自己的容器类。。。总而言之,ACE是一个庞然大物,威力无穷,但也显得比较笨重。C++发展到现在,库的设计风格也越来越趋向于泛型,boost就是一个典型,而且boost社区跟C++标准委员会的密切关系,使得进入boost的程序库有更大的机会加入下一代的C++标准库。因此不管从设计风格(我不否认我也喜欢追时髦;)),还是从功利的角度看,学习asio都是一笔不错的投资。学习她,首先要安装她。asio要求首先安装boost,下面我把自己的安装过程描述一遍,这确实还是颇费心思的。首先要先安装boost,这可是一个漫长而又炎热的夏天。。。万幸的是我以前已经装过了,嘿嘿。我装的是boost_1_33_0,为了完整说明,我这里也简单列了下boost的安装步骤,这也是从网上找来的。step1.从下载boost库step2 在 tools\build\jam_src目录下 运行build.bat来生成jamstep3 设置环境变量(后面的%PATH%要加)PATH=%boost的绝对路径%\tools\build\jam_src\bin.ntx86;%PATH%&PATH=%boost的绝对路径%;%PATH%For Visial Studio 6.0&SET MSVC_ROOT="VC6的安装路径"&SET VISUALC="VC6的安装路径"&Example:&SET MSVC_ROOT="c:\Program Files\Microsoft Visual Studio\VC98"For Visual Studio.net&SET VC7_ROOT="vs.NET安装路径"&Example:&SET VC7_ROOT="C:\Program Files\Microsoft Visual Studio .NET\VC7"For Visual Studio.net 2003&SET VC71_ROOT="vs.NET2003安装路径"&Example:&set VC71_ROOT="C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7"step 4 编译boost库&bjam "-sTOOLS=%编译器%" installVisual Studio 6.0 %编译器%=msvc&Visual Studio .NET %编译器%=vc7&Visual Studio .NET 2003 %编译器%=vc-7_1我用的是VC7.1,照着这个指示,当时编译了好久才完成。不过我在最后一步时,忘了加上install。这也没什么,你可以在boost下新建一个lib文件夹,然后把bin目录下所有的库文件都拷贝进来,然后在你的编译器里进行适当的路径设置(头文件路径,库文件路径),就可以使用boost了。安装好boost后(我装在了E:\boost_1_33_0),就可以安装asio了,先去下载,现在是最新版本0.3.8。注意下载带有boost前缀(boost_asio_0_3_8rc2.zip)的zip文件,解开后可以看到两个目录:boost和libs。把boost里面的所有文件拷贝到E:\boost_1_33_0\boost下面,注意里面有个detail目录不能直接覆盖,而是要把其中的文件(identifier.hpp)拷贝到E:\boost_1_33_0\boost\detail中去;同样把libs里面的文件夹都拷贝到E:\boost_1_33_0\libs下,就可以了。好了,接下来就到了激动人心的时刻,让我们来开始编译asio示例,我找了个asio自带的最简单的例子,关于同步定时器的,5秒后超时打印Hello, world!#include &iostream&#include &boost/asio.hpp&#include &boost/date_time/posix_time/posix_time.hpp&int main(){&&&&&& boost::asio::io_&&&&&& boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));&&&&&& t.wait();&&&&&& std::cout && "Hello, world!\n";&&&&&& return 0;}先别管具体的代码,开始编译。。。果然不出所料,哪有那么顺畅的事情;)正在编译...main.cppe:\boost_1_33_0\boost\asio\detail\push_options.hpp(103) : fatal error C1189: #error :&&&&&& Multithreaded RTL must be selected.哦,原来需要多线程库,这好办,在项目属性里:配置属性 -& C/C++ -& 代码生成 -& 运行时库 -&多线程调试(/MTd),再试一下。正在编译...main.cppPlease define _WIN32_WINNT or _WIN32_WINDOWS appropriatelyAssuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)正在链接...LINK : fatal error LNK1104: 无法打开文件&libboost_system-vc71-mt-sgd-1_33.lib&好家伙,一下出来俩。第一个是windows版本支持问题,我在项目属性里把宏_WIN32_WINNT加到预处理器中,现在编译通过了,但链接还是不行:正在链接...LINK : fatal error LNK1104: 无法打开文件&libboost_system-vc71-mt-sgd-1_33.lib&找不到system库。我纳闷了一会,因为asio主页上明明写着大部分功能只需要boost头文件即可。因此我又照着asio主页上的说明,把_BOOST_ALL_NO_LIB也加到预处理器中去,但还是不行。后来我又到下载的文件中去找,发现system是asio自带的一个库,要想使用asio,就必须先编译这个库,OMG~我还没单独编译过boost的一个库,因此又去网上找了找,终于找到了,原来也不是很难。基本步骤还是跟编译整个boost一样,只不过在最后一步时,要换成这样:bjam "-sTOOLS=%编译器%" --with-system install就可以编译system库了。最后检查下编译器的头文件和库文件路径是否正确,再重新试一遍,终于大功告成!我怀着欣喜的心情开始测试asio自带的tutorial程序,前面几个关于定时器的运行的很正常,但到了后来测试daytime1的时候,链接又有问题了。正在编译...main.cppf:\My-SmartWin-Demo\asio_demo\main.cpp(56) : warning C4267: &参数& : 从&size_t&转换到&std::streamsize&,可能丢失数据正在链接...main.obj : error LNK2019: 无法解析的外部符号 "public: static class boost::system::error_category __cdecl boost::system::error_code::new_category(int (__cdecl*)(class boost::system::error_code const &),class std::basic_string&char,struct std::char_traits&char&,class std::allocator&char& & (__cdecl*)(class boost::system::error_code const &),class std::basic_string&unsigned short,struct std::char_traits&unsigned short&,class std::allocator&unsigned short& & (__cdecl*)(class boost::system::error_code const &))" (?new_category@error_code@system@boost@@SA?AVerror_category@23@P6AHABV123@@ZP6A?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@ZP6A?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@6@0@Z@Z) ,该符号在函数 _$E47 中被引用Debug/asio_demo.exe : fatal error LNK1120: 1 个无法解析的外部命令前面那个警告不管,后面链接时说一个static函数new_category(...)只有声明没有实现,我找了下,这个函数在system库里error_code.hpp中有声明,error_code.cpp也有实现,而且明明system库我也编译成功,并加入相关路径中,怎么还是会出错?郁闷了半天,后来干脆把error_code.cpp加入到daytime1工程中一起编译,终于彻底搞定了。真是TMD不容易啊。
对于一个网络程序的服务器端我们需要提供的是服务器的address,和服务开放的端口号port。在asio库中首先我们必须使用一个io_service类来支持所有的IO功能。需要注意到是我们必须调用io_service_my.run()函数来开启IO服务的事件循环以使功能都能被正常使用。boost::asio::io_service io_service_现在我们可以基于这个io_service_my来关联构建一下几个类:1. boost::asio::ip::tcp::acceptor acceptor_my(io_service_my);&因为LPD的实现是基于TCP传输协议,所以也使用了TCP的acceptor来接收client发来的连接。2.&&boost::asio::ip::tcp::resolver resolver_my(io_service_my);boost::asio::ip::tcp::resolver::query query_my(address,port);boost::asio::ip::tcp::endpoint endpoint_my = *resolver.resolve(query_my);这几个类主要是用来实现对地址的解析和绑定终端节点到相应的开放端口号上。首先构造一个关联到io_service_my的解析器resolver_my。然后让解析器resolver_my执行resolve()函数来解析query_my指定的address和port到一个终端节点endpoint_my上。我们会看到这个endpoint_my终端节点会被绑定到这个acceptor_my接收器上。3. boost::asio::ip::tcp::socket socket_my(io_service_my);定义一个基于TCP协议的socket关联到io_service_my对象上。在这些准备工作做完后我们开始一些实际的动作:/** 打开一个使用由endpoint_my指定的协议类型的接收器,这个protocol()函数会自动返回与endpoint_my关联的协* 议类型。*/acceptor_my.open(endpoint_my.protocol());/** 设置选项允许socket绑定到一个已经正在被使用的地址。*/acceptor_my.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true);/** 把接收器绑定到已经被设置过的endpoint_my。*/acceptor_my.bind(endpoint_my);/** 接收器开始侦听。*/acceptor_my.listen();/** 以同步/异步方式开始接收连接。*/acceptor_my.accept(socket_my) //同步acceptor_my.async_accept(socket_my,&&boost::bind(&handle_accept,boost::asio::placeholders::error));//异步其中异步的侦听函数原型是:template&&&&&typename SocketService,&&&&typename AcceptHandler&void async_accept(&&&&basic_socket& protocol_type, SocketService & & peer,&&&&AcceptHandler handler);handler所对应的函数在新连接接收完成后会被调用。这种异步方式实现回调的方法也类似于使用boost::asio::io_service::post(boost::bind(&handle_accept));注意到bind函数中的&handle_accept,这是函数handle_accept的入口地址,也就是在接收完成后会调用的函数在这里我们可以继续进行下一步的处理,从socket_my中读取或者写入数据。/** 调用异步读函数,把接收的数据拷贝到buffer缓存中,其中buffer是由参数buffer_my构造,* 而buffer_my本身可以是一个容器例如boost::array&char,8192& buffer_my,表示申请了* 一个8K个char字符型空间。也可以使用例外一种方法实现buffer的构造例如* boost::asio::buffer(data,size_t);其中data表示指向某种数据类型的指针,* size_t则表示包含多少个该数据类型的元素。*/void handle_accept(boost::system::error_code error){if(!error){&&boost::array&char, 8192& buffer_&&boost::asio::async_read(socket_my, boost::asio::buffer(buffer_my),&& boost::bind(&handle_read, boost::asio::placeholders::error));}&}类似的写程序如下boost::asio::async_write(socket_my, boost::asio::buffer(buffer_my),&& boost::bind(&handle_write,&&&&& boost::asio::placeholders::error,&&&& boost::asio::placeholders::bytes_transferred));最后在所有连接完成之后或是服务器停止的时候别忘记关掉连接。例如socket_my.close();acceptor_my.close();至此一个基于boost::asio库的网络程序的框架就出来了,至于具体的设计类实现可以视需求而定。
摘要:本文通过形像而活泼的语言简单地介绍了Boost::asio库的使用,作为asio的一个入门介绍是非常合适的,可以给人一种新鲜的感觉,同时也能让体验到asio的主要内容。本文来自网络,原文在这里。目录 [隐藏]ASIO的同步方式自我介绍示例代码小结ASIO的异步方式自我介绍示例代码小结ASIO的&便民措施&端点超时统一读写接口基于流的操作用ASIO编写UDP通信程序用ASIO读写串行口演示代码Boost.Asio是一个跨平台的网络及底层IO的C++编程库,它使用现代C++手法实现了统一的异步调用模型。ASIO的同步方式ASIO库能够使用TCP、UDP、ICMP、串口来发送/接收数据,下面先介绍TCP协议的读写操作。对于读写方式,ASIO支持同步和异步两种方式,首先登场的是同步方式,下面请同步方式自我介绍一下。自我介绍大家好!我是同步方式!我的主要特点就是执着!所有的操作都要完成或出错才会返回,不过偶的执着被大家称之为阻塞,实在是郁闷~~(场下一片嘘声),其实这样 也是有好处的,比如逻辑清晰,编程比较容易。在服务器端,我会做个socket交给acceptor对象,让它一直等客户端连进来,连上以后再通过这个socket与客户端通信, 而所有的通信都是以阻塞方式进行的,读完或写完才会返回。在客户端也一样,这时我会拿着socket去连接服务器,当然也是连上或出错了才返回,最后也是以阻塞的方式和服务器通信。有人认为同步方式没有异步方式高效,其实这是片面的理解。在单线程的情况下可能确实如此,我不能利用耗时的网络操作这段时间做别的事 情,不是好的统筹方法。不过这个问题可以通过多线程来避免,比如在服务器端让其中一个线程负责等待客户端连接,连接进来后把socket交给另外的线程去 和客户端通信,这样与一个客户端通信的同时也能接受其它客户端的连接,主线程也完全被解放了出来。我的介绍就有这里,谢谢大家!示例代码好,感谢同步方式的自我介绍,现在放出同步方式的演示代码(起立鼓掌!)。服务器端#include &iostream&#include &boost/asio.hpp&int main(int argc, char* argv[]){&&&&&&&&using namespace boost::&&&&&&&&// 所有asio类都需要io_service对象&&&&&&&&io_&&&&&&&&ip::tcp::acceptor acceptor(iosev,&&&&&&&&&ip::tcp::endpoint(ip::tcp::v4(), 1000));&&&&&&&&for(;;)&&&&&&&&{&&&&&&&&&&&&&&&&// socket对象&&&&&&&&&&&&&&&&ip::tcp::socket socket(iosev);&&&&&&&&&&&&&&&&// 等待直到客户端连接进来&&&&&&&&&&&&&&&&acceptor.accept(socket);&&&&&&&&&&&&&&&&// 显示连接进来的客户端&&&&&&&&&&&&&&&&std::cout && socket.remote_endpoint().address() && std::&&&&&&&&&&&&&&&&// 向客户端发送hello world!&&&&&&&&&&&&&&&&boost::system::error_&&&&&&&&&&&&&&&&socket.write_some(buffer("hello world!"), ec);&&&&&&&&&&&&&&&&// 如果出错,打印出错信息&&&&&&&&&&&&&&&&if(ec)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&std::cout &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&boost::system::system_error(ec).what() && std::&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&// 与当前客户交互完成后循环继续等待下一客户连接&&&&&&&&}&&&&&&&&return 0;}客户端#include &iostream&#include &boost/asio.hpp&int main(int argc, char* argv[]){&&&&&&&&using namespace boost::&&&&&&&&// 所有asio类都需要io_service对象&&&&&&&&io_&&&&&&&&// socket对象&&&&&&&&ip::tcp::socket socket(iosev);&&&&&&&&// 连接端点,这里使用了本机连接,可以修改IP地址测试远程连接&&&&&&&&ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 1000);&&&&&&&&// 连接服务器&&&&&&&&boost::system::error_&&&&&&&&socket.connect(ep,ec);&&&&&&&&// 如果出错,打印出错信息&&&&&&&&if(ec)&&&&&&&&{&&&&&&&&&&&&&&&&std::cout && boost::system::system_error(ec).what() && std::&&&&&&&&&&&&&&&&return -1;&&&&&&&&}&&&&&&&&// 接收数据&&&&&&&&char buf[100];&&&&&&&&size_t len=socket.read_some(buffer(buf), ec);&&&&&&&&std::cout.write(buf, len);&&&&&&&&return 0;}小结从演示代码可以得知ASIO的TCP协议通过boost::asio::ip名 空间下的tcp类进行通信。IP地址(address,address_v4,address_v6)、 端口号和协议版本组成一个端点(tcp:: endpoint)。用于在服务器端生成tcp::acceptor对 象,并在指定端口上等待连接;或者在客户端连接到指定地址的服务器上。socket是 服务器与客户端通信的桥梁,连接成功后所有的读写都是通过socket对 象实现的,当socket析 构后,连接自动断 开。ASIO读写所用的缓冲区用buffer函 数生成,这个函数生成的是一个ASIO内部使用的缓冲区类,它能把数组、指针(同时指定大 小)、std::vector、std::string、boost::array包装成缓冲区类。ASIO中的函数、类方法都接受一个boost::system::error_code类 型的数据,用于提供出错码。它可以转换成bool测试是否出错,并通过boost::system::system_error类 获得详细的出错信息。另外,也可以不向ASIO的函数或方法提供 boost::system::error_code,这时如果出错的话就会直 接抛出异常,异常类型就是boost::system:: system_error(它是从std::runtime_error继承的)。ASIO的异步方式嗯?异步方式好像有点坐不住了,那就请异步方式上场,大家欢迎...自我介绍大家好,我是异步方式和同步方式不同,我从来不花时间去等那些龟速的IO操作,我只是向系统说一声要做什么,然后就可以做其它事去了。如果系统完成了操作, 系统就会通过我之前给它的回调对象来通知我。在ASIO库中,异步方式的函数或方法名称前面都有&async_& 前缀,函数参数里会要求放一个回调函数(或仿函数)。异步操作执行 后不管有没有完成都会立即返回,这时可以做一些其它事,直到回调函数(或仿函数)被调用,说明异步操作已经完成。在ASIO中很多回调函数都只接受一个boost::system::error_code参数,在实际使用时肯定是不够的,所以一般 使用仿函数携带一堆相关数据作为回调,或者使用boost::bind来绑定一堆数据。另外要注意的是,只有io_service类的run()方法运行之后回调对象才会被调用,否则即使系统已经完成了异步操作也不会有任 务动作。示例代码好了,就介绍到这里,下面是我带来的异步方式TCP Helloworld 服务器端:#include &iostream&#include &string&#include &boost/asio.hpp&#include &boost/bind.hpp&#include &boost/smart_ptr.hpp&using namespace boost::using boost::system::error_using ip::struct CHelloWorld_Service{&&&&&&&&CHelloWorld_Service(io_service &iosev)&&&&&&&&&&&&&&&&:m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))&&&&&&&&{}&&&&&&&&void start()&&&&&&&&{&&&&&&&&&&&&&&&&// 开始等待连接(非阻塞)&&&&&&&&&&&&&&&&boost::shared_ptr&tcp::socket& psocket(new tcp::socket(m_iosev));&&&&&&&&&&&&&&&&// 触发的事件只有error_code参数,所以用boost::bind把socket绑定进去&&&&&&&&&&&&&&&&m_acceptor.async_accept(*psocket,&&&&&&&&&&&&&&&&&&&&&&&&boost::bind(&CHelloWorld_Service::accept_handler, this, psocket, _1));&&&&&&&&}&&&&&&&&// 有客户端连接时accept_handler触发&&&&&&&&void accept_handler(boost::shared_ptr&tcp::socket& psocket, error_code ec)&&&&&&&&{&&&&&&&&&&&&&&&&if(ec)&&&&&&&&&&&&&&&&// 继续等待连接&&&&&&&&&&&&&&&&start();&&&&&&&&&&&&&&&&// 显示远程IP&&&&&&&&&&&&&&&&std::cout && psocket-&remote_endpoint().address() && std::&&&&&&&&&&&&&&&&// 发送信息(非阻塞)&&&&&&&&&&&&&&&&boost::shared_ptr&std::string& pstr(new std::string("hello async world!"));&&&&&&&&&&&&&&&&psocket-&async_write_some(buffer(*pstr),&&&&&&&&&&&&&&&&&&&&&&&&boost::bind(&CHelloWorld_Service::write_handler, this, pstr, _1, _2));&&&&&&&&}&&&&&&&&// 异步写操作完成后write_handler触发&&&&&&&&void write_handler(boost::shared_ptr&std::string& pstr, error_code ec,&&&&&&&&&&&&&&&&size_t bytes_transferred)&&&&&&&&{&&&&&&&&&&&&&&&&if(ec)&&&&&&&&&&&&&&&&std::cout&& "发送失败!" && std::&&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&std::cout&& *pstr && " 已发送" && std::&&&&&&&&}&&&&&&&&private:&&&&&&&&&&&&&&&&io_service &m_&&&&&&&&&&&&&&&&ip::tcp::acceptor m_};int main(int argc, char* argv[]){&&&&&&&&io_&&&&&&&&CHelloWorld_Service sev(iosev);&&&&&&&&// 开始等待连接&&&&&&&&sev.start();&&&&&&&&iosev.run();&&&&&&&&return 0;}小结在这个例子中,首先调用sev.start()开 始接受客户端连接。由于async_accept调 用后立即返回,start()方 法 也就马上完成了。sev.start()在 瞬间返回后iosev.run()开 始执行,iosev.run()方法是一个循环,负责分发异步回调事件,只 有所有异步操作全部完成才会返回。这里有个问题,就是要保证start()方法中m_acceptor.async_accept操 作所用的tcp::socket对 象 在整个异步操作期间保持有效(不 然系统底层异步操作了一半突然发现tcp::socket没了,不是拿人家开涮嘛-_-!!!),而且客户端连接进来后这个tcp::socket对象还 有用呢。这里的解决办法是使用一个带计数的智能指针boost::shared_ptr,并把这个指针作为参数绑定到回调函数上。一旦有客户连接,我们在start()里给的回调函数accept_handler就会被 调用,首先调用start()继续异步等待其 它客户端的连接,然后使用绑定进来的tcp::socket对象与当前客户端通信。发送数据也使用了异步方式(async_write_some), 同样要保证在整个异步发送期间缓冲区的有效性,所以也用boost::bind绑定了boost::shared_ptr。对于客户端也一样,在connect和read_some方法前加一个async_前缀,然后加入回调即可,大家自己练习写一写。ASIO的&便民措施&asio中提供一些便利功能,如此可以实现许多方便的操作。端点回到前面的客户端代码,客户端的连接很简单,主要代码就是两行:...// 连接socket.connect(endpoint,ec);...// 通信socket.read_some(buffer(buf), ec);不过连接之前我们必须得到连接端点endpoint,也就是服务器地址、端口号以及所用的协议版本。前面的客户端代码假设了服务器使用IPv4协议,服务器IP地址为127.0.0.1,端口号为1000。实际使用的情况是,我们经常只能知道服务器网络ID,提供的服务类型,这时我们就得使用ASIO提供的tcp::resolver类来取得服务器的端点了。比如我们要取得163网站的首页,首先就要得到&www.163.com&服务器的HTTP端点:io_ip::tcp::resolver res(iosev);ip::tcp::resolver::query query("www.163.com","80"); //www.163.com 80端口ip::tcp::resolver::iterator itr_endpoint = res.resolve(query);这里的itr_endpoint是一个endpoint的迭代器,服务器的同一端口上可能不止一个端点,比如同时有IPv4和IPv6 两种。现在,遍历这些端点,找到可用的:// 接上面代码ip::tcp::resolver::iterator itr_ //无参数构造生成end迭代器ip::tcp::socket socket(iosev);boost::system::error_code ec = error::host_not_for(;ec && itr_endpoint!=itr_++itr_endpoint){&&&&&&&&socket.close();&&&&&&&&socket.connect(*itr_endpoint, ec);}如果连接上,错误码ec被清空,我们就可以与服务器通信了:if(ec){&&&&&&&&std::cout && boost::system::system_error(ec).what() && std::&&&&&&&&return -1;}// HTTP协议,取根路径HTTP源码socket.write_some(buffer("GET &a href="http://www.163.com" title="http://www.163.com"&http://www.163.com&/a& HTTP/1.0 "));for(;;){&&&&&&&&char buf[128];&&&&&&&&boost::system::error_&&&&&&&&size_t len = socket.read_some(buffer(buf), error);&&&&&&&&// 循环取数据,直到取完为止&&&&&&&&if(error == error::eof)&&&&&&&&&&&&&&&&else if(error)&&&&&&&&{&&&&&&&&&&&&&&&&std::cout && boost::system::system_error(error).what() && std::&&&&&&&&&&&&&&&&return -1;&&&&&&&&}&&&&&&&&std::cout.write(buf, len);}当所有HTTP源码下载了以后,服务器会主动断开连接,这时客户端的错误码得到boost::asio::error::eof,我们 要根据它来判定是否跳出循环。ip::tcp::resolver::query的构造函数接受服务器名和服务名。前面的服务名我们直接使用了端口号"80",有时 我们也可以使用别名,用记事本打开%windir%\system32\drivers\etc\services文件(Windows环境),可以看到 一堆别名及对应的端口,如:echo&&&&&&&&&& 7/tcp&&&&&&&&&&&&&&&& # Echoftp&&&&&&&&&& 21/tcp&&&&&&&&&&&&&&&& # File Transfer Protocol (Control)telnet&&&&&&&&23/tcp&&&&&&&&&&&&&&&& # Virtual Terminal Protocolsmtp&&&&&&&&&&25/tcp&&&&&&&&&&&&&&&& # Simple Mail Transfer Protocoltime&&&&&&&&&&37/tcp&&timeserver&&&& # Time比如要连接163网站的telnet端口(如果有的话),可以这样写:ip::tcp::resolver::query query("www.163.com","telnet");ip::tcp::resolver::iterator itr_endpoint = res.resolve(query);超时在网络应用里,常常要考虑超时的问题,不然连接后半天没反应谁也受不了。ASIO库提供了deadline_timer类来支持定时触发,它的用法是:// 定义定时回调void print(const boost::system::error_code& /*e*/){&&&&&&&&std::cout && "Hello, world! ";}deadline_// 设置5秒后触发回调timer.expires_from_now(boost::posix_time::seconds(5));timer.async_wait(print);这段代码执行后5秒钟时打印Hello World!我们可以利用这种定时机制和异步连接方式来实现超时取消:deadline_// 异步连接socket.async_connect(my_endpoint, connect_handler/*连接回调*/);// 设置超时timer.expires_from_now(boost::posix_time::seconds(5));timer.async_wait(timer_handler);...// 超时发生时关闭socketvoid timer_handler(){&&&&&&&&socket.close();}最后不要忘了io_service的run()方法。统一读写接口除了前面例子所用的tcp::socket读写方法(read_some, write_some等)以外,ASIO也提供了几个读写函数,主要有这么几个:read、write、read_until、write_until当然还有异步版本的async_read、async_write、async_read_until、async_write_until这些函数可以以统一的方式读写TCP、串口、HANDLE等类型的数据流。我们前面的HTTP客户端代码可以这样改写:...//socket.write_some(buffer("GET &a href="http://www.163.com" title="http://www.163.com"&http://www.163.com&/a& HTTP/1.0 "));write(socket,buffer("GET &a href="http://www.163.com" title="http://www.163.com"&http://www.163.com&/a& HTTP/1.0 "));...//size_t len = socket.read_some(buffer(buf), error);size_t len = read(socket, buffer(buf), transfer_all() ,error);if(len) std::cout.write(buf, len);这个read和write有多个重载,同样,有错误码参数的不会抛出异常而无错误码参数的若出错则抛出异常。本例中read函数里的transfer_all()是一个称为CompletionCondition的对象,表示读取/写入直接缓 冲区装满或出错为止。另一个可选的是transfer_at_least(size_t),表示至少要读取/写入多少个字符。read_until和write_until用于读取直到某个条件满足为止,它接受的参数不再是buffer,而是boost::asio:: streambuf。比如我们可以把我们的HTTP客户端代码改成这样:boost::asio::size_t len = read_until(socket,strmbuf," ",error);std::istream is(&strmbuf);is.unsetf(std::ios_base::skipws);// 显示is流里的内容std::copy(std::istream_iterator&char&(is),&&&&std::istream_iterator&char&(),&&&&std::ostream_iterator&char&(std::cout));基于流的操作对于TCP协议来说,ASIO还提供了一个tcp::iostream。用它可以更简单地实现我们的HTTP客户端:ip::tcp::iostream stream("www.163.com", "80");if(stream){&&&&&&&&// 发送数据&&&&&&&&stream && "GET &a href="http://www.163.com" title="http://www.163.com"&http://www.163.com&/a& HTTP/1.0 ";&&&&&&&&// 不要忽略空白字符&&&&&&&&stream.unsetf(std::ios_base::skipws);&&&&&&&&// 显示stream流里的内容&&&&&&&&std::copy(std::istream_iterator&char&(stream),&&&&&&&&std::istream_iterator&char&(),&&&&&&&&std::ostream_iterator&char&(std::cout));}用ASIO编写UDP通信程序ASIO的TCP协议通过boost::asio::ip名空间下的tcp类进行通信,举一返三:ASIO的UDP协议通过boost::asio::ip名空间下的udp类进行通信。我们知道UDP是基于数据报模式的,所以事先不需要建立连接。就象寄信一样,要寄给谁只要写上地址往门口的邮箱一丢,其它的事各级邮局 包办;要收信用只要看看自家信箱里有没有信件就行(或问门口传达室老大爷)。在ASIO里,就是udp::socket的send_to和receive_from方法(异步版本是async_send_to和asnync_receive_from)。下面的示例代码是从ASIO官方文档里拿来的(实在想不出更好的例子了:-P):服务器端代码//// server.cpp// ~~~~~~~~~~//// Copyright (c)
Christopher M. Kohlhoff&// (chris at kohlhoff dot com)//// Distributed under the Boost Software License, Version 1.0.&// (See accompanying// file LICENSE_1_0.txt or&// copy at &a href="http://www.boost.org/LICENSE_1_0.txt" title="http://www.boost.org/LICENSE_1_0.txt"&http://www.boost.org/LICENSE_1_0.txt&/a&)//#include &ctime&#include &iostream&#include &string&#include &boost/array.hpp&#include &boost/asio.hpp&using boost::asio::ip::std::string make_daytime_string(){&&&&&&&& // For time_t,&&&&&&&&time_t now = time(0);&&&&&&&&return ctime(&now);}int main(){&&&&&&&&try&&&&&&&&{&&&&&&&&&&&&&&&&boost::asio::io_service io_&&&&&&&&&&&&&&&&// 在本机13端口建立一个socket&&&&&&&&&&&&&&&&udp::socket socket(io_service, udp::endpoint(udp::v4(), 13));&&&&&&&&&&&&&&&&for (;;)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&boost::array&char, 1& recv_&&&&&&&&&&&&&&&&&&&&&&&&udp::endpoint remote_&&&&&&&&&&&&&&&&&&&&&&&&boost::system::error_&&&&&&&&&&&&&&&&&&&&&&&&// 接收一个字符,这样就得到了远程端点(remote_endpoint)&&&&&&&&&&&&&&&&&&&&&&&&socket.receive_from(boost::asio::buffer(recv_buf),&&&&&&&&&&&&&&&&&&&&&&&&remote_endpoint, 0, error);&&&&&&&&&&&&&&&&&&&&&&&&if (error && error != boost::asio::error::message_size)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&throw boost::system::system_error(error);&&&&&&&&&&&&&&&&&&&&&&&&std::string message = make_daytime_string();&&&&&&&&&&&&&&&&&&&&&&&&// 向远程端点发送字符串message(当前时间)&&&&&&&&&&&&&&&&&&&&&&&&&&&&boost::system::error_code ignored_&&&&&&&&&&&&&&&&&&&&&&&&socket.send_to(boost::asio::buffer(message),&&&&&&&&&&&&&&&&&&&&&&&&remote_endpoint, 0, ignored_error);&&&&&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&catch (std::exception& e)&&&&&&&&{&&&&&&&&&&&&&&&&std::cerr && e.what() && std::&&&&&&&&}&&&&&&&&return 0;}客户端代码//// client.cpp// ~~~~~~~~~~//// Copyright (c)
Christopher M. Kohlhoff// (chris at kohlhoff dot com)//// Distributed under the Boost Software License, Version 1.0.&// (See accompanying file LICENSE_1_0.txt or//&&copy at &a href="http://www.boost.org/LICENSE_1_0.txt" title="http://www.boost.org/LICENSE_1_0.txt"&http://www.boost.org/LICENSE_1_0.txt&/a&)//#include &iostream&#include &boost/array.hpp&#include &boost/asio.hpp&using boost::asio::ip::int main(int argc, char* argv[]){&&&&&&&&try&&&&&&&&{&&&&&&&&&&&&&&&&if (argc != 2)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&&&&&std::cerr && "Usage: client &host&" && std::&&&&&&&&&&&&&&&&&&&&&&&&return 1;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&boost::asio::io_service io_&&&&&&&&&&&&&&&&// 取得命令行参数对应的服务器端点&&&&&&&&&&&&&&&&udp::resolver resolver(io_service);&&&&&&&&&&&&&&&&udp::resolver::query query(udp::v4(), argv[1], "daytime");&&&&&&&&&&&&&&&&udp::endpoint receiver_endpoint = *resolver.resolve(query);&&&&&&&&&&&&&&&&udp::socket socket(io_service);&&&&&&&&&&&&&&&&socket.open(udp::v4());&&&&&&&&&&&&&&&&// 发送一个字节给服务器,让服务器知道我们的地址&&&&&&&&&&&&&&&&boost::array&char, 1& send_buf&&= { 0 };&&&&&&&&&&&&&&&&socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);&&&&&&&&&&&&&&&&// 接收服务器发来的数据&&&&&&&&&&&&&&&&boost::array&char, 128& recv_&&&&&&&&&&&&&&&&udp::endpoint sender_&&&&&&&&&&&&&&&&size_t len = socket.receive_from(&&&&&&&&&&&&&&&&boost::asio::buffer(recv_buf), sender_endpoint);&&&&&&&&&&&&&&&&std::cout.write(recv_buf.data(), len);&&&&&&&&}&&&&&&&&catch (std::exception& e)&&&&&&&&{&&&&&&&&&&&&&&&&std::cerr && e.what() && std::&&&&&&&&}&&&&&&&&return 0;}用ASIO读写串行口ASIO不仅支持网络通信,还能支持串口通信。要让两个设备使用串口通信,关键是要设置好正确的参数,这些参数是:波特率、奇偶校验 位、停止位、字符大小和流量控制。两个串口设备只有设置了相同的参数才能互相交谈。ASIO提供了boost::asio::serial_port类,它有一个set_option(const SettableSerialPortOption& option)方法就是用于设置上面列举的这些参数的,其中的option可以是:serial_port::baud_rate 波特率,构造参数为unsigned intserial_port::parity 奇偶校验,构造参数为serial_port::parity::type,enum类型,可以是none, odd, even。serial_port::flow_control 流量控制,构造参数为serial_port::flow_control::type,enum类型,可以是none software hardwareserial_port::stop_bits 停止位,构造参数为serial_port::stop_bits::type,enum类型,可以是one onepointfive twoserial_port::character_size 字符大小,构造参数为unsigned int演示代码#include &iostream&#include &boost/asio.hpp&#include &boost/bind.hpp&using namespace boost::int main(int argc, char* argv[]){&&&&&&&&io_&&&&&&&&// 串口COM1, Linux下为&/dev/ttyS0&&&&&&&&&serial_port sp(iosev, "COM1");&&&&&&&&// 设置参数&&&&&&&&sp.set_option(serial_port::baud_rate(19200));&&&&&&&&sp.set_option(serial_port::flow_control(serial_port::flow_control::none));&&&&&&&&sp.set_option(serial_port::parity(serial_port::parity::none));&&&&&&&&sp.set_option(serial_port::stop_bits(serial_port::stop_bits::one));&&&&&&&&sp.set_option(serial_port::character_size(8));&&&&&&&&// 向串口写数据&&&&&&&&write(sp, buffer("Hello world", 12));&&&&&&&&// 向串口读数据&&&&&&&&char buf[100];&&&&&&&&read(sp, buffer(buf));&&&&&&&&iosev.run();&&&&&&&&return 0;}上面这段代码有个问题,read(sp, buffer(buf))非得读满100个字符才会返回,串口通信有时我们确实能知道对方发过来的字符长度,有时候是不能的。如果知道对方发过来的数据里有分隔符的话(比如空格作为分隔),可以使用read_until来读,比如:boost::asio::// 一直读到遇到空格为止read_until(sp, buf, ' ');copy(istream_iterator&char&(istream(&buf)&&noskipws),&&&&&&&&istream_iterator&char&(),&&&&&&&&ostream_iterator&char&(cout));另外一个方法是使用前面说过的异步读写+超时的方式,代码如下:#include &iostream&#include &boost/asio.hpp&#include &boost/bind.hpp&using namespace boost::void handle_read(char *buf,boost::system::error_code ec,std::size_t bytes_transferred){&&&&&&&&cout.write(buf, bytes_transferred);}int main(int argc, char* argv[]){&&&&&&&&io_&&&&&&&&serial_port sp(iosev, "COM1");&&&&&&&&sp.set_option(serial_port::baud_rate(19200));&&&&&&&&sp.set_option(serial_port::flow_control());&&&&&&&&sp.set_option(serial_port::parity());&&&&&&&&sp.set_option(serial_port::stop_bits());&&&&&&&&sp.set_option(serial_port::character_size(8));&&&&&&&&write(sp, buffer("Hello world", 12));&&&&&&&&// 异步读&&&&&&&&char buf[100];&&&&&&&&async_read(sp, buffer(buf), boost::bind(handle_read, buf, _1, _2));&&&&&&&&// 100ms后超时&&&&&&&&deadline_timer timer(iosev);&&&&&&&&timer.expires_from_now(boost::posix_time::millisec(100));&&&&&&&&// 超时后调用sp的cancel()方法放弃读取更多字符&&&&&&&&timer.async_wait(boost::bind(&serial_port::cancel, boost::ref(sp)));&&&&&&&&iosev.run();&&&&&&&&return 0;}
asio自带的例子里是用deadline_timer的async_wait方法来实现超时的,这种方法需要单独写一个回调函数,不利于把连接和超时封装到单个函数里。传统的Winsock编程可以先把socket设为非阻塞,然后connect,再用select来判断超时,asio也可以这样做,唯一&非主流&的是asio里没有一个类似select的函数,所以得调用原始的Winsock API,也就牺牲了跨平台:
#include&&iostream& &
#include&&boost/asio.hpp& &
int&main() &
&&&&boost::asio::io_service& &
&&&&boost::asio::ip::tcp::socket&s(ios); &
&&&&boost::system::error_code& &
&&&&s.open(boost::asio::ip::tcp::v4()); &
&&&&s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(true)); &
&&&&s.connect( &
&&&&&&&&boost::asio::ip::tcp::endpoint( &
&&&&&&&&boost::asio::ip::address::from_string("192.168.1.1"),&80) &
&&&&&&&&,&ec); &
&&&&fd_set&fdW &
&&&&FD_ZERO(&fdWrite); &
&&&&FD_SET(s.native(),&&fdWrite); &
&&&&timeval&tv&=&{5};&&&&
&&&&if&(select(0,&NULL,&&fdWrite,&NULL,&&tv)&&=&0& &
&&&&&&&&||&!FD_ISSET(s.native(),&&fdWrite)) &
&&&&&&&&std::cout&&&&"超时/出错啦"&&&&std:: &
&&&&&&&&s.close(); &
&&&&&&&&return&0; &
&&&&s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(false)); &
&&&&std::cout&&&&"连接成功"&&&&std:: &
&&&&s.close(); &
&&&&return&0; &
所有的 asio 类都只要包含头文件:&& "asio.hpp"例子1:&& 使用一个同步的定时器#include &iostream&#include &boost/asio.hpp&#include &boost/date_time/posix_time/posix_time.hpp&&& //使用时间间隔int main(){//所有使用 asio 的程序都必须至少拥有一个 io_service 类型的对象.&//它提供 I/O 功能.&boost::asio::io_//创建一个定时器 deadline_timer 的对象.&//这种定时器有两种状态: 超时 和 未超时.//在超时的状态下. 调用它的 wait() 函数会立即返回.&//在未超时的情况下则阻塞. 直到变为超时状态.//它的构造函数参数为: 一个 io_service 对象(asio中主要提供IO的类都用io_service对象做构造函数第一个参数).//&&&&&&&&&&&&&&&&&&&& 超时时间.//从创建开始. 它就进入 "未超时"状态. 且持续指定的时间. 转变到"超时"状态.boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));//这里等待定时器 t 超时. 所以会阻塞5秒.t.wait();std::cout && "Hello, world!\n";return 0;}例子2: 使用一个异步的定时器//一个将被定时器异步调用的函数.&void print(const boost::system::error_code& /*e*/){std::cout && "Hello, world!\n";}int main(){boost::asio::io_boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));//和例子1不同. 这里调用 async_wait() 执行一个异步的等待. 它注册一个可执行体(即此处的print函数).&& //这里不懂的是: print的参数怎么传入?//实际上. 这个执行体被注册到 deadline_timer 类的 io_service 成员上(即本例的 io 对象). 只有在以后调用 io.run() 时这些注册的执行体才会被真正执行.&t.async_wait(print);//调用 io对象的 run() 函数执行那些被注册的执行体.&//这个函数不会立即返回. 除非和他相关的定时器对象超时并且在定时器超时后执行完所有注册的执行体. 之后才返回.&//所以它在这里阻塞一会儿. 等t超时后执行完print. 才返回.//这里要注意的是. 调用 io.run() 可以放在其它线程中. 那样所有的回调函数都在别的线程上运行.io.run();return 0;}例子3: 向超时回调函数绑定参数// 这个例子中. 每次 定时器超时后. 都修改定时器的状态到"未超时". 再注册回调函数. 这样循环 5 次. 所以 print 会被执行 5 次.void print(const boost::system::error_code& /*e*/,&&&&boost::asio::deadline_timer* t, int* count){if (*count & 5){&&&&std::cout && *count && "\n";&&&&++(*count);&&&&//可以用 deadline_timer::expires_at() 来 获取/设置 超时的时间点.&&&&&//在这里我们将超时的时间点向后推迟一秒.&&&&&t-&expires_at(t-&expires_at() + boost::posix_time::seconds(1));&&&&//再次向 t 中的 io_service 对象注册一个回掉函数.&&&&&// 注意这里绑定时. 指定了绑定到 print 的第一个参数为: boost::asio::placeholders::error //不懂. 这个error是什么东西. 为什么在例子2中不要绑定它?&&&&t-&async_wait(boost::bind(print,&&&&&&&&&&boost::asio::placeholders::error, t, count));}}int main(){boost::asio::io_int count = 0;boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));t.async_wait(boost::bind(print,&&&&&&&&boost::asio::placeholders::error, &t, &count));io.run();std::cout && "Final count is " && count && "\n";return 0;}例子4: 多线程处理定时器的回掉函数. 同步的问题.前面的例子都只在一个线程中调用 boost::asio::io_service::run() 函数.&向定时器注册的回掉函数都是在调用该 run() 的线程中执行.但实际上这个 run() 函数可以在多个线程中同时被调用. 例如:boost::asio::io_&//两个定时器boost::asio::deadline_timer t1(io, boost::posix_time::seconds(1));t1.async_wait(func1);&&&boost::asio::deadline_timer t2(io, boost::posix_time::seconds(1));t2.async_wait(func2);&由于向 io 注册了多个cmd. 这里为了效率我们想让这些cmd并行执行:boost::thread thread1(bind(&boost::asio::io_service::run, &io);boost::thread thread2(bind(&boost::asio::io_service::run, &io);thread1.join();thread2.join();这里在多个线程中调用 io.run() 所以我们注册的cmd可能在任何一个线程中运行.&这些线程会一直等待io对象相关的定时器超时并执行相关的 cmd. 直到所有的定时器都超时. run函数才返回. 线程才结束.但这里有一个问题: 我们向定时器注册的 func1 和 func2 . 它们可能会同时访问全局的对象(比如 cout ).&这时我们希望对 func1 和 func2 的调用是同步的. 即执行其中一个的时候. 另一个要等待.这就用到了 boost::asio::strand 类. 它可以把几个cmd包装成同步执行的. 例如前面我们向定时器注册 func1 和 func2 时. 可以改为:boost::asio::strand the_t1.async_wait(the_strand.wrap(func1));&&&&&&//包装为同步执行的t2.async_wait(the_strand.wrap(func2));&这样就保证了在任何时刻. func1 和 func2 都不会同时在执行.
#include&"stdafx.h"&&
#include&&boost/asio.hpp&&&
#include&&boost/bind.hpp&&&
#include&&boost/date_time/posix_time/posix_time_types.hpp&&&
#include&&iostream&&&
using&namespace&boost::&&
using&boost::asio::ip::&&
class&connect_handler&&
&&&&connect_handler(io_service&&ios)&&
&&&&&&&&:&io_service_(ios),&&
&&&&&&&&timer_(ios),&&
&&&&&&&&socket_(ios)&&
&&&&&&&&socket_.async_connect(&&
&&&&&&&&&&&&tcp::endpoint(boost::asio::ip::address_v4::loopback(),&3212),&&
&&&&&&&&&&&&boost::bind(&connect_handler::handle_connect,&this,&&
&&&&&&&&&&&&boost::asio::placeholders::error));&&
&&&&&&&&timer_.expires_from_now(boost::posix_time::seconds(5));&&
&&&&&&&&timer_.async_wait(boost::bind(&connect_handler::close,&this));&&
&&&&void&handle_connect(const&boost::system::error_code&&err)&&
&&&&&&&&if&(err)&&
&&&&&&&&{&&
&&&&&&&&&&&&std::cout&&&&"Connect&error:&"&&&&err.message()&&&&"\n";&&
&&&&&&&&}&&
&&&&&&&&else&&
&&&&&&&&{&&
&&&&&&&&&&&&std::cout&&&&"Successful&connection\n";&&
&&&&&&&&}&&
&&&&void&close()&&
&&&&&&&&socket_.close();&&
private:&&
&&&&io_service&&io_service_;&&
&&&&deadline_timer&timer_;&&
&&&&tcp::socket&socket_;&&
int&main()&&
&&&&&&&&io_service&&&
&&&&&&&&tcp::acceptor&a(ios,&tcp::endpoint(tcp::v4(),&32123),&1);&&
&&&&&&&&connect_handler&ch1(ios);&&
&&&&&&&&ios.run();&&
&&&&catch&(std::exception&&e)&&
&&&&&&&&std::cerr&&&&"Exception:&"&&&&e.what()&&&&"\n";&&
&&&&return&0;&&
服务器代码:Servier.cpp#include &boost/asio.hpp&#include &boost/bind.hpp&#include &boost/shared_ptr.hpp&#include &boost/enable_shared_from_this.hpp&#include &iostream&using boost::asio::ip::#define max_len 1024class clientSession:public boost::enable_shared_from_this&clientSession&{public:clientSession(boost::asio::io_service& ioservice):m_socket(ioservice){memset(data_,&\0&,sizeof(data_));}~clientSession(){}tcp::socket& socket(){return m_}void start(){boost::asio::async_write(m_socket,boost::asio::buffer(&link successed!&),boost::bind(&clientSession::handle_write,shared_from_this(),boost::asio::placeholders::error));/*async_read跟客户端一样,还是不能进入handle_read函数,如果你能找到问题所在,请告诉我,谢谢*/// --已经解决,boost::asio::async_read(...)读取的字节长度不能大于数据流的长度,否则就会进入// ioservice.run()线程等待,read后面的就不执行了。//boost::asio::async_read(m_socket,boost::asio::buffer(data_,max_len),//&&&&&&&& boost::bind(&clientSession::handle_read,shared_from_this(),//&&&&&&&& boost::asio::placeholders::error));//max_len可以换成较小的数字,就会发现async_read_some可以连续接收未收完的数据m_socket.async_read_some(boost::asio::buffer(data_,max_len),boost::bind(&clientSession::handle_read,shared_from_this(),boost::asio::placeholders::error));}private:void handle_write(const boost::system::error_code& error){if(error){m_socket.close();}}void handle_read(const boost::system::error_code& error){if(!error){std::cout && data_ && std:://boost::asio::async_read(m_socket,boost::asio::buffer(data_,max_len),//&&&& boost::bind(&clientSession::handle_read,shared_from_this(),//&&&& boost::asio::placeholders::error));m_socket.async_read_some(boost::asio::buffer(data_,max_len),boost::bind(&clientSession::handle_read,shared_from_this(),boost::asio::placeholders::error));}else{m_socket.close();}}private:tcp::socket m_char data_[max_len];};class serverApp{typedef boost::shared_ptr&clientSession& session_public:serverApp(boost::asio::io_service& ioservice,tcp::endpoint& endpoint):m_ioservice(ioservice),acceptor_(ioservice,endpoint){session_ptr new_session(new clientSession(ioservice));acceptor_.async_accept(new_session-&socket(),boost::bind(&serverApp::handle_accept,this,boost::asio::placeholders::error,new_session));}~serverApp(){}private:void handle_accept(const boost::system::error_code& error,session_ptr& session){if(!error){std::cout && &get a new client!& && std:://实现对每个客户端的数据处理session-&start();//在这就应该看出为什么要封session类了吧,每一个session就是一个客户端session_ptr new_session(new clientSession(m_ioservice));acceptor_.async_accept(new_session-&socket(),boost::bind(&serverApp::handle_accept,this,boost::asio::placeholders::error,new_session));}}private:boost::asio::io_service& m_tcp::acceptor acceptor_;};int main(int argc , char* argv[]){boost::asio::io_service myIoSshort port = 8100/*argv[1]*/;//我们用的是inet4tcp::endpoint endPoint(tcp::v4(),port);//终端(可以看作sockaddr_in)完成后,就要accept了serverApp sa(myIoService,endPoint);//数据收发逻辑myIoService.run();return 0;}客户端代码:#include &boost/asio.hpp&#include &boost/bind.hpp&#include &boost/shared_ptr.hpp&using boost::asio::ip::class client{public:client(boost::asio::io_service& io_service,tcp::endpoint& endpoint): socket(io_service)//这里就把socket实例化了{//连接服务端 connectsocket.async_connect(endpoint,boost::bind(&client::handle_connect,this,boost::asio::placeholders::error));memset(getBuffer,&\0&,1024);}~client(){}private:void handle_connect(const boost::system::error_code& error){if(!error){//一连上,就向服务端发送信息boost::asio::async_write(socket,boost::asio::buffer(&hello,server!&),boost::bind(&client::handle_write,this,boost::asio::placeholders::error));/**读取服务端发下来的信息*这里很奇怪,用async_read根本就不能进入handle_read函数**/// --已经解决,boost::asio::async_read(...)读取的字节长度不能大于数据流的长度,否则就会进入// ioservice.run()线程等待,read后面的就不执行了。//boost::asio::async_read(socket,//&&&& boost::asio::buffer(getBuffer,1024),//&&&& boost::bind(&client::handle_read,this,boost::asio::placeholders::error)//&&&&);socket.async_read_some(boost::asio::buffer(getBuffer,1024),boost::bind(&client::handle_read,this,boost::asio::placeholders::error));}else{socket.close();}}void handle_read(const boost::system::error_code& error){if(!error){std::cout && getBuffer && std:://boost::asio::async_read(socket,//&&&&&&&& boost::asio::buffer(getBuffer,1024),//&&&&&&&& boost::bind(&client::handle_read,this,boost::asio::placeholders::error)//&&&&&&&&);//这样就可以实现循环读取了,相当于while(1)//当然,到了这里,做过网络的朋友就应该相当熟悉了,一些逻辑就可以自行扩展了//想做聊天室的朋友可以用多线程来实现socket.async_read_some(boost::asio::buffer(getBuffer,1024),boost::bind(&client::handle_read,this,boost::asio::placeholders::error));}else{socket.close();}}void handle_write(const boost::system::error_code& error){}private:tcp::char getBuffer[1024];};int main(int argc,char* argv[]){//if(argc != 3)//{// std::cerr && &Usage: chat_client &host& &port&\n&;//&&&&return 1;//}//我觉IO_SERVICE是一个基本性的接口,基本上通常用到的类实例都需要通过它来构造//功能我们可以看似socketboost::asio::io_service io_//这个终端就是服务器//它的定义就可以看作时sockaddr_in,我们用它来定义IP和PORTtcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("192.168.1.119"/*argv[1]*/),8100/*argv[2]*/);//既然socket和sockaddr_in已经定义好了,那么,就可以CONNECT了//之所以为了要把连接和数据处理封成一个类,就是为了方便管理数据,这点在服务端就会有明显的感觉了boost::shared_ptr&client& client_ptr(new client(io_service,endpoint));//执行收发数据的函数io_service.run();return 0;}修改192.168.1.119为127.0.0.1,然后先运行server,再运行client,一切ok.
理论基础许多应用程序以某种方式和外界交互,例如文件,网络,串口或者终端。某些情况下例如网络,独立IO操作需要很长时间才能完成,这对程序开发形成了一个特殊的挑战。Boost.Asio库提供管理这些长时间操作的工具,并且不需要使用基于线程的并发模型和显式的锁。Asio库致力于如下几点:移植性高负载效率基于已知API例如BSD sockets的模型概念易于使用作为进一步抽象的基础虽然asio主要关注网络,它的异步概念也扩展到了其他系统资源,例如串口,文件等等。主要概念和功能基本架构(略)Proactor设计模式:无需额外线程的并发机制(略)这种模型感觉很像aio或者iocp,而select,epoll则应该类似于Reactor。线程和Asio线程安全一般来说,并发使用不同的对象是安全的。但并发使用同一个对象是不安全的。不过io_service等类型的并发使用是安全的。线程池多个线程可以同时调用io_service::run,多个线程是平等的。内部线程为了某些特定功能,asio内部使用了thread以模拟异步,这些thread对用户而言是不可见的。它们都符合如下原则:它们不会直接调用任何用户代码他们不会被任何信号中断。注意,如下几种情况违背了原则1。ip::basic_resolver::async_resolve() 所有平台basic_socket::async_connect() windows平台涉及null_buffers()的任何操作 windows平台以上是容易理解的,asio本身尽可能不创建thread,某些情况下,例如connect,由于windows 2k平台下并不提供异步connect,所以asio只能用select模拟,这种情况下不得不创建新线程。windows xp下提供connectex,但考虑到兼容性,asio似乎并未使用。asio完全保证然后异步完成函数都仅在运行io_service::run的线程中被调用。同时,创建并且管理运行io_service::run的线程是用户的责任。Strands:使用多线程且无需显式锁有3种方式可以显式或隐式使用锁。只在一个线程中调用io_service::run,那么所有异步完成函数都会在该线程中串行化调用应用逻辑保证直接使用strandstrand::wrap可以创建一个包裹handler用于post或其他异步调用。BuffersAsio支持多个buffer同时用于读写,类似于WSARecv里面的WSABUF数组。mutable_buffer和const_buffer类似于WSABUF,MutableBufferSequence和ConstBufferSequence类似于WSABUF的容器。Buffer本身不分配释放内存,该数据结构很简单。vc8及以上的编译器在debug编译时缺省支持检查越界等问题。其他编译器可以用BOOST_ASIO_DISABLE_BUFFER_DEBUGGING打开这个开关。流,不完全读和不完全写许多io对象是基于流的,这意味着:没有消息边界,数据是连续的字节。读或者写操作可能仅传送了要求的部分字节,这称之为不完全读/写。read_some,async_read_some,write_some,async_write_some则为这种不完全读/写。系统API一般均为这种不完全读写。例如WSASend,WSARecv等等。一般来说都需要读/写特定的字节。可以用read,async_read,write,async_write。这些函数在未完成任务之前会持续调用不完全函数。EOFread,async_read,read_until,async_read_until在遇到流结束时会产生一个错误。这是很合理的,例如要求读4个字节,但仅读了1个字节socket就关闭了。在handle_read中error_code将提示一个错误。Reactor类型的操作有些应用程序必须集成第3方的库,这些库希望自己执行io操作。这种操作类似于select,考察select和aio的区别,前者是得到完成消息,然后再执行同步读操作,aio是预发异步读操作,在完成消息到来时,读操作已经完成。null_buffer设计用来实现这类操作。ip::tcp::socket socket(my_io_service);...ip::tcp::socket::non_blocking nb(true);socket.io_control(nb);...socket.async_read_some(null_buffers(), read_handler);...void read_handler(boost::system::error_code ec){&&if (!ec)&&{&&&&std::vector&char& buf(socket.available());&&&&socket.read_some(buffer(buf));&&}}注意一般asio的用法和这明显不同。以上代码非常类似select的方式。常规代码是:boost::asio::async_read(socket_,boost::asio::buffer(data,length),handle_read);void handle_read(){&}行操作许多应用协议都是基于行的,例如HTTP,SMTP,FTP。为了简化这类操作,Asio提供read_until以及async_read_until。例如:class http_connection{&&...&&void start()&&{&&&&boost::asio::async_read_until(socket_, data_, "/r/n",&&&&&&&&boost::bind(&http_connection::handle_request_line, this, _1));&&}&&void handle_request_line(boost::system::error_code ec)&&{&&&&if (!ec)&&&&{&&&&&&std::string method, uri,&&&&&&char sp1, sp2, cr,&&&&&&std::istream is(&data_);&&&&&&is.unsetf(std::ios_base::skipws);&&&&&&is && method && sp1 && uri && sp2 && version && cr &&&&&&&&...&&&&}&&}&&...&&boost::asio::ip::tcp::socket socket_;&&boost::asio::streambuf data_;};read_until,async_read_until支持的判断类型可以是char,string以及boost::regex,它还支持自定义匹配函数。以下例子是持续读,一直到读到空格为止:typedef boost::asio::buffers_iterator&&&&&boost::asio::streambuf::const_buffers_type&std::pair&iterator, bool&match_whitespace(iterator begin, iterator end){&&iterator i =&&while (i != end)&&&&if (std::isspace(*i++))&&&&&&return std::make_pair(i, true);&&return std::make_pair(i, false);}...boost::asio::boost::asio::read_until(s, b, match_whitespace);以下例子是持续读,直到读到特定字符为止:class match_char{public:&&explicit match_char(char c) : c_(c) {}&&template &typename Iterator&&&std::pair&Iterator, bool& operator()(&&&&&&Iterator begin, Iterator end) const&&{&&&&Iterator i =&&&&while (i != end)&&&&&&if (c_ == *i++)&&&&&&&&return std::make_pair(i, true);&&&&return std::make_pair(i, false);&&}private:&&char c_;};namespace boost { namespace asio {&&template && struct is_match_condition&match_char&&&&&: public boost::true_type {};} } // namespace boost::asio...boost::asio::boost::asio::read_until(s, b, match_char('a'));自定义内存分配Asio很多地方都需要复制拷贝handlers,缺省情况下,使用new/delete,如果handlers提供void* asio_handler_allocate(size_t, ...);void asio_handler_deallocate(void*, size_t, ...);则会调用这两个函数来进行分配和释放。The implementation guarantees that the deallocation will occur before the associated handler is invoked, which means the memory is ready to be reused for any new asynchronous operations started by the handler.如果在完成函数中再发起一个异步请求,那么这块内存可以重用,也就是说,如果永远仅有一个异步请求在未完成的状态,那么仅需要一块内存就足够用于asio的handler copy了。The custom memory allocation functions may be called from any user-created thread that is calling a library function. The implementation guarantees that, for the asynchronous operations included the library, the implementation will not make concurrent calls to the memory allocation functions for that handler. The implementation will insert appropriate memory barriers to ensure correct memory visibility should allocation functions need to be called from different threads.以上这段不很清楚,不明白多线程环境下,asio_handler_allocate是否要考虑同步问题。Custom memory allocation support is currently implemented for all asynchronous operations with the following exceptions:ip::basic_resolver::async_resolve() on all platforms.basic_socket::async_connect() on Windows.Any operation involving null_buffers() on Windows, other than an asynchronous read performed on a stream-oriented socket.
boost::asio是一个高性能的网络开发库,Windows下使用IOCP,Linux下使用epoll。与ACE不同的是,它并没有提供一个网络框架,而是采取组件的方式来提供应用接口。但是对于常见的情况,采用一个好用的框架还是能够简化开发过程,特别是asio的各个异步接口的用法都相当类似。  受到 SP Server 框架的影响,我使用asio大致实现了一个多线程的半异步半同步服务器框架,以下是利用它来实现一个Echo服务器:1. 实现回调:static void onSessionStarted(RequestPtr const& request, ResponsePtr const& response) {&& request-&setReadMode(Session::READ_LN); // 设置为行读取}static void onSession(RequestPtr const& request, ResponsePtr const& response) {&& print(request-&message()); //打印收到的消息&& response-&addReply(request-&message()); //回送消息&& response-&close();}复制代码说明:close()是一个关闭请求,它并不马上关闭Session,而是等待所有与该Session相关的异步操作全部结束后才关闭。2. 一个单线程的Echo服务器:void server_main() {unsigned short port = 7;AsioSAsioTcpServer tcp(svc, port);svc.callbacks().sessionStarted = &onSessionSsvc.callbacks().sessionHandle = &onSsvc.run();}复制代码3. 一个多线程的Echo服务器(半异步半同步:一个主线程,4个工作者线程)void server_main2() {unsigned short port = 7;int num_threads = 4;AsioSAsioService worker(AsioService::HAS_WORK);AsioTcpServer tcp(svc, port);svc.callbacks().sessionStarted = worker.wrap(&onSessionStarted);svc.callbacks().sessionHandle = worker.wrap(&onSession);AsioThreadPool thr(worker, num_threads);svc.run();}复制代码  有了这样一个思路,实现起来就很容易了。重点是以下两点:  1。缓冲区的管理与内存池的使用  2。为了保证Session的线程安全,必须要设置一个挂起状态。&&&&&&&&   还有一个好处,就是完全隔绝了asio的应用接口,不用再忍受asio漫长的编译时间了。代码就不贴在这里了,有兴趣的可以通过email 探讨。(说明,这里只提出一个思路,不再提供源代码,请各位见谅)
2. 同步Timer本章介绍asio如何在定时器上进行阻塞等待(blocking wait).&实现,我们包含必要的头文件.&所有的asio类可以简单的通过include "asio.hpp"来调用.#include &iostream&#include &boost/asio.hpp&此外,这个示例用到了timer,我们还要包含Boost.Date_Time的头文件来控制时间.#include &boost/date_time/posix_time/posix_time.hpp&使用asio至少需要一个boost::asio::io_service对象.该类提供了访问I/O的功能.我们首先在main函数中声明它.int main(){&&&&boost::asio::io_下一步我们声明boost::asio::deadline_timer对象.这个asio的核心类提供I/O的功能(这里更确切的说是定时功能),总是把一个io_service对象作为他的第一个构造函数,而第二个构造函数的参数设定timer会在5秒后到时(expired).boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));这个简单的示例中我们演示了定时器上的一个阻塞等待.就是说,调用boost::asio::deadline_timer::wait()的在创建后5秒内(注意:不是等待开始后),timer到时之前不会返回任何值.&一个deadline_timer只有两种状态:到时,未到时.&如果boost::asio::deadline_timer::wait()在到时的timer对象上调用,会立即return.t.wait();最后,我们输出理所当然的"Hello, world!"来演示timer到时了.&&&&std::cout && "Hello, world! ";&&&&return 0;}完整的代码:#include &iostream&#include &boost/asio.hpp&#include &boost/date_time/posix_time/posix_time.hpp&int main(){&&&&boost::asio::io_&&&&boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));&&&&t.wait();&&&&std::cout && "Hello, world! ";&&&&return 0;}3. 异步Timer#include &iostream&#include &asio.hpp&#include &boost/date_time/posix_time/posix_time.hpp&asio的异步函数会在一个异步操作完成后被回调.这里我们定义了一个将被回调的函数.void print(const asio::error& /*e*/){&&&&std::cout && "Hello, world! ";}int main(){&&&&asio::io_&&&&asio::deadline_timer t(io, boost::posix_time::seconds(5));这里我们调用asio::deadline_timer::async_wait()来异步等待t.async_wait(print);最后,我们必须调用asio::io_service::run().&asio库只会调用那个正在运行的asio::io_service::run()的回调函数.&如果asio::io_service::run()不被调用,那么回调永远不会发生.&asio::io_service::run()会持续工作到点,这里就是timer到时,回调完成.&别忘了在调用 asio::io_service::run()之前设置好io_service的任务.比如,这里,如果我们忘记先调用asio::deadline_timer::async_wait()则asio::io_service::run()会在瞬间return.&&&&io.run();&&&&return 0;}完整的代码:#include &iostream&#include &asio.hpp&#include &boost/date_time/posix_time/posix_time.hpp&void print(const asio::error& /*e*/){&&&&std::cout && "Hello, world! ";}int main(){&&&&asio::io_&&&&asio::deadline_timer t(io, boost::posix_time::seconds(5));&&&&t.async_wait(print);&&&&io.run();&&&&return 0;}4. 回调函数的参数这里我们将每秒回调一次,来演示如何回调函数参数的含义#include &iostream&#include &asio.hpp&#include &boost/bind.hpp&#include &boost/date_time/posix_time/posix_time.hpp&首先,调整一下timer的持续时间,开始一个异步等待.显示,回调函数需要访问timer来实现周期运行,所以我们再介绍两个新参数指向timer的指针一个int*来指向计数器void print(const asio::error& /*e*/,&&&&asio::deadline_timer* t, int* count){我们打算让这个函数运行6个周期,然而你会发现这里没有显式的方法来终止io_service.不过,回顾上一节,你会发现当 asio::io_service::run()会在所有任务完成时终止.这样我们当计算器的值达到5时(0为第一次运行的值),不再开启一个新的异步等待就可以了.&&&&if (*count & 5)&&&&{&&&&&&&&std::cout && *count && " ";&&&&&&&&++(*count);...然后,我们推迟的timer的终止时间.通过在原先的终止时间上增加延时,我们可以确保timer不会在处理回调函数所需时间内的到期.&(原文:By calculating the new expiry time relative to the old, we can ensure that the timer does not drift away from the whole-second mark due to any delays in processing the handler.)t-&expires_at(t-&expires_at() + boost::posix_time::seconds(1));然后我们开始一个新的同步等待.如您所见,我们用把print和他的多个参数用boost::bind函数合成一个的形为void(const asio::error&)回调函数(准确的说是function object).&在这个例子中, boost::bind的asio::placeholders::error参数是为了给回调函数传入一个error对象.当进行一个异步操作,开始 boost::bind时,你需要使用它来匹配回调函数的参数表.下一节中你会学到回调函数不需要error参数时可以省略它.&&&& t-&async_wait(boost::bind(print,&&&&&&&&asio::placeholders::error, t, count));&&&&}}int main(){&&&&asio::io_&&&&int count = 0;&&&&asio::deadline_timer t(io, boost::posix_time::seconds(1));和上面一样,我们再一次使用了绑定asio::deadline_timer::async_wait()t.async_wait(boost::bind(print,&&&&asio::placeholders::error, &t, &count));io.run();在结尾,我们打印出的最后一次没有设置timer的调用的count的值&&&&std::cout && "Final count is " && count && " ";&&&&return 0;}完整的代码:#include &iostream&#include &asio.hpp&#include &boost/bind.hpp&#include &boost/date_time/posix_time/posix_time.hpp&void print(const asio::error& /*e*/,&&&&&& asio::deadline_timer* t, int* count){&&&&if (*count & 5)&&&&{&&&&&&&&std::cout && *count && " ";&&&&&&&&++(*count);&&&&&&&&t-&expires_at(t-&expires_at() + boost::posix_time::seconds(1));&&&&&&&&t-&async_wait(boost::bind(print,&&&&&&&&&&&&&&&&&&&&asio::placeholders::error, t, count));&&&&}}int main(){&&&&asio::io_&&&&int count = 0;&&&&asio::deadline_timer t(io, boost::posix_time::seconds(1));&&&&t.async_wait(boost::bind(print,&&&&&&&&&&&&&&&&asio::placeholders::error, &t, &count));&&&&io.run();&&&&std::cout && "Final count is " && count && " ";&&&&return 0;}5. 成员函数作为回调函数本例的运行结果和上一节类似#include &iostream&#include &boost/asio.hpp&#include &boost/bind.hpp&#include &boost/date_time/posix_time/posix_time.hpp&我们先定义一个printer类class printer{public://构造函数有一个io_service参数,并且在初始化timer_时用到了它.用来计数的count_这里同样作为了成员变量&&&&printer(boost::asio::io_service& io)&&&&&&&&: timer_(io, boost::posix_time::seconds(1)),&&&&&&&&&&&&count_(0)&&&&{boost::bind 同样可以出色的工作在成员函数上.众所周知,所有的非静态成员函数都有一个隐式的this参数,我们需要把this作为参数bind到成员函数上.和上一节类似,我们再次用bind构造出void(const boost::asio::error&)形式的函数.&注意,这里没有指定boost::asio::placeholders::error占位符,因为这个print成员函数没有接受一个error对象作为参数.timer_.async_wait(boost::bind(&printer::print, this));在类的折构函数中我们输出最后一次回调的count的值~printer(){&&&&std::cout && "Final count is " && count_ && " ";}print函数于上一节的十分类似,但是用成员变量取代了参数.&&&&void print()&&&&{&&&&&&&&if (count_ & 5)&&&&&&&&{&&&&&&&&&&&&std::cout && count_ && " ";&&&&&&&&&&&&++count_;&&&&&&&&&&&&timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));&&&&&&&&&&&&timer_.async_wait(boost::bind(&printer::print, this));&&&&&&&&}&&&&}private:&&&&boost::asio::deadline_timer timer_;&&&&int count_;};现在main函数清爽多了,在运行io_service之前只需要简单的定义一个printer对象.int main(){&&&&boost::asio::io_&&&&printer p(io);&&&&io.run();&&&&return 0;}完整的代码:#include &iostream&#include &boost/asio.hpp&#include &boost/bind.hpp&#include &boost/date_time/posix_time/posix_time.hpp&class printer{&&&&public:&&&&&&&&printer(boost::asio::io_service& io)&&&&&&&&&&&&: timer_(io, boost::posix_time::seconds(1)),&&&&&&&&&&&&count_(0)&&&&{&&&&&&&&timer_.async_wait(boost::bind(&printer::print, this));&&&&}&&&&&&&&~printer()&&&&&&&&{&&&&&&&&&&&&std::cout && "Final count is " && count_ && " ";&&&&&&&&}&&&&&&&&void print()&&&&&&&&{&&&&&&&&&&&&if (count_ & 5)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&std::cout && count_ && " ";&&&&&&&&&&&&&&&&++count_;&&&&&&&&&&&&&&&&timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));&&&&&&&&&&&&&&&&timer_.async_wait(boost::bind(&printer::print, this));&&&&&&&&&&&&}&&&&&&&&}&&&&private:&&&&&&&&boost::asio::deadline_timer timer_;&&&&&&&&int count_;};int main(){&&&&boost::asio::io_&&&&printer p(io);&&&&io.run();&&&&return 0;}6. 多线程回调同步本节演示了使用boost::asio::strand在多线程程序中进行回调同步(synchronise).&先前的几节阐明了如何在单线程程序中用boost::asio::io_service::run()进行同步.如您所见,asio库确保 仅当当前线程调用boost::asio::io_service::run()时产生回调.显然,仅在一个线程中调用 boost::asio::io_service::run() 来确保回调是适用于并发编程的.&一个基于asio的程序最好是从单线程入手,但是单线程有如下的限制,这一点在服务器上尤其明显:当回调耗时较长时,反应迟钝.在多核的系统上无能为力如果你发觉你陷入了这种困扰,可以替代的方法是建立一个boost::asio::io_service::run()的线程池.然而这样就允许回调函数并发执行.所以,当回调函数需要访问一个共享,线程不安全的资源时,我们需要一种方式来同步操作.#include &iostream&#include &boost/asio.hpp&#include &boost/thread.hpp&#include &boost/bind.hpp&#include &boost/date_time/posix_time/posix_time.hpp&在上一节的基础上我们定义一个printer类,此次,它将并行运行两个timerclass printer{public:除了声明了一对boost::asio::deadline_timer,构造函数也初始化了类型为boost::asio::strand的strand_成员.&boost::asio::strand 可以分配的回调函数.它保证无论有多少线程调用了boost::asio::io_service::run(),下一个回调函数仅在前一个回调函数完成后开始,当然回调函数仍然可以和那些不使用boost::asio::strand分配,或是使用另一个boost::asio::strand分配的回调函数一起并发执行.printer(boost::asio::io_service& io)&&&&: strand_(io),&&&&timer1_(io, boost::posix_time::seconds(1)),&&&&timer2_(io, boost::posix_time::seconds(1)),&&&&count_(0){当一个异步操作开始时,用boost::asio::strand来 "wrapped(包装)"回调函数.boost::asio::strand::wrap()会返回一个由boost::asio::strand分配的新的handler(句柄),这样,我们可以确保它们不会同时运行.&&&&timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));&&&&timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));}~printer(){&&&&std::cout && "Final count is " && count_ && " ";}多线程程序中,回调函数在访问共享资源前需要同步.这里共享资源是std::cout 和count_变量.&&&&&void print1()&&&&{&&&&&&&&if (count_ & 10)&&&&&&&&{&&&&&&&&&&&&std::cout && "Timer 1: " && count_ && " ";&&&&&&&&&&&&++count_;&&&&&&&&&&&&timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));&&&&&&&&&&&&timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));&&&&&&&&}&&&&}&&&&void print2()&&&&{&&&&&&&&if (count_ & 10)&&&&&&&&{&&&&&&&&&&&&std::cout && "Timer 2: " && count_ && " ";&&&&&&&&&&&&++count_;&&&&&&&&&&&&timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));&&&&&&&&&&&&timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));&&&&&&&&}&&&&}private:&&&&boost::asio::strand strand_;&&&&boost::asio::deadline_timer timer1_;&&&&boost::asio::deadline_timer timer2_;&&&&int count_;};main函数中boost::asio::io_service::run()在两个线程中被调用:主线程、一个boost::thread线程.&正如单线程中那样,并发的boost::asio::io_service::run()会一直运行直到完成任务.后台的线程将在所有异步线程完成后终结.&int main(){&&&&boost::asio::io_&&&&printer p(io);&&&&boost::thread t(boost::bind(&boost::asio::io_service::run, &io));&&&&io.run();&&&&t.join();&&&&return 0;}完整的代码:#include &iostream&#include &boost/asio.hpp&#include &boost/thread.hpp&#include &boost/bind.hpp&#inclu

我要回帖

更多关于 春风650mt 测评 的文章

 

随机推荐