Boost.Asio c++ 网络编程翻译(6)

io_service类

你应该已经发现大部分使用Boost.Asio编写的代码都会使用几个ios_service的实例。ios_service是这个库里面最重要的类;它负责和操作系统打交道,等待所有异步操作的结束,然后为每一个异步操作调用完成处理程序。

如果你选择用同步的方式来创建你的应用,你不需要考虑我将在这一节向你展示的东西。

你可以用几种不同的方式来使用io_service。在下面的例子中,我们有3个异步操作,2个socket连接和一个计时器等待:

有一个io_service和一个处理线程的单线程例子:

io_service service_;

// all the socket operations are handled by service_

ip::tcp::socket sock1(service_);

// all the socket operations are handled by service_

ip::tcp::socket sock2(service_);

sock1.async_connect( ep, connect_handler);

sock2.async_connect( ep, connect_handler);

deadline_timer t(service_, boost::posix_time::seconds(5));

t.async_wait(timeout_handler);

service_.run();

有单个io_service实例和多个处理线程的多线程例子:

io_service service_;

ip::tcp::socket sock1(service_);

ip::tcp::socket sock2(service_);

sock1.async_connect( ep, connect_handler);

sock2.async_connect( ep, connect_handler);

deadline_timer t(service_, boost::posix_time::seconds(5));

t.async_wait(timeout_handler);

for ( int i = 0; i < 5; ++i)

boost::thread( run_service);

void run_service() {

service_.run();

}

有多个io_service实例和多个处理线程的多线程例子:

io_service service_[2];

ip::tcp::socket sock1(service_[0]);

ip::tcp::socket sock2(service_[1]);

sock1.async_connect( ep, connect_handler);

sock2.async_connect( ep, connect_handler);

deadline_timer t(service_[0], boost::posix_time::seconds(5));

t.async_wait(timeout_handler);

for ( int i = 0; i < 2; ++i)

boost::thread( boost::bind(run_service, i));

void run_service(int idx) {

service_[idx].run();

}

首先,要注意你不能拥有多个io_service却只有一个线程。下面的代码片段没有任何意义:

for ( int i = 0; i < 2; ++i)

service_[i].run();

上面的代码片段没有意义是因为service_[1].run()需要service_[0].run()先结束。因此,所有由service_[1]处理的异步操作都需要等待,这显然不是一个好主意。

在前面的3个方案中,我们在等待3个异步操作结束。为了解释之间的不同点,我们假设:过一会操作1完成,然后接着操作2完成。同时我们假设每一个完成处理程序需要1秒钟来完成执行。

在第一个例子中,我们在一个线程中等待三个操作全部完成,只要第1个操作完成,我们调用它的完成处理程序。尽管操作2紧接着完成了,操作2的完成处理程序需要在1秒钟后操作1的完成处理程序完成才被调用。

第二个例子,我们在两个线程中等待3个异步操作结束。当操作1完成时,我们在第一个线程中调用它的完成处理程序。当操作2完成时,紧接着,我们就在第二个线程中调用它的完成处理函数(当线程1在忙着响应操作1的处理程序时,线程2空闲着并且可以回应任何新进来的操作)。

在第三个例子中,因为操作1是sock1的connect,操作2是sock2的connect,所以应用程序会表现得像第二个例子一样。线程1会处理sock1 connect操作的完成处理程序,线程2会处理sock2的connect操作的完成处理程序。然而,如果sock1的connect操作是操作1,deadline_timer t的超时操作是操作2,线程1会结束正在处理的sock1 connect操作的完成处理程序。因而,deadline_timer
t的超时操作必须等sock1 connect操作的完成处理程序结束(等待1秒钟),因为线程1要处理sock1的连接处理程序和t的超时处理程序。

下面是你需要从前面的例子中学到的:

第一种情况是非常基础的应用程序。因为是串行的方式,所以当几个处理程序要被同时调用时,你会经常遇到瓶颈。如果一个处理程序需要花费很长的时间来执行,所有随后的处理程序都不得不等待。

第二种情况是比较适用的应用程序。他是非常强壮的——如果几个处理程序被同时调用了(这是有可能的),它们会在各自的线程里面被调用。唯一的瓶颈就是所有的处理线程都很忙的同时又有新的处理程序被调用。然而,这有快速的解决方式,增加处理线程的数目即可。

第三种情况最复杂和最难理解的。你只有在第二种情况不能满足需求时才使用它。这种情况一般就是当你有成千上万实时(socket)连接时。你可以认为每一个处理线程(运行io_service::run()的线程)有它自己的select/epoll循环;它等待任何一个socket,然后监控一个读写操作,当它发现这种操作时,就执行。大部分情况下,你不需要担心什么,唯一你需要担心的就是当你监控的socket数目以指数级的方式增长时(超过1000个的socket)。在那种情况下,有几个select/epoll循环会增加响应时间。

如果你觉得你成应用程序可能需要转换到第三种模式,请确保监听操作的这段代码(调用io_service::run()的代码)和应用程序其他部分是隔离的,这样你就可以很轻松的对其进行更改。

最后,要一直记住如果没有其他需要监控的操作,.run()就会结束,就像下面给的代码片段:

io_service service_;

tcp::socket sock(service_);

sock.async_connect( ep, connect_handler);

service_.run();

在上面的例子,只要sock建立了一个连接,connect_handler就会被调用,然后接着service_.run()就会完成执行。

如果你想要service_.run()接着执行,你需要分配更多的工作给它。这里有两个方式来完成这个目标。一种方式是在connect_handler中启动另外一个异步操作来分配更多的工作。

另一种方式模拟一些工作给它,用下面的代码片段:

typedef boost::shared_ptr<io_service::work> work_ptr;

work_ptr dummy_work(new io_service::work(service_));

上面的代码可以保证service_.run()一直运行直到你调用useservice_.stop()或者

dummy_work.reset(0);// 销毁 dummy_work.

总结

Boost.Asio是一个复杂的库,但是却让网络编程变得异常简单。编译它很简单。它避免使用宏,这一点做得很好;他虽然定义了少部分的宏来做选项开关,但是你需要担心的很少。

Bosot.Asio支持同步和异步编程。他们有很大不同;你需要早早地选择其中的一种,因为它们之间的转换是非常复杂而且易错的。

如果你选择同步,你可以选择异常处理或者错误码,从异常处理转到错误码;只需要在call函数中增加一个参数即可(错误码)。

Boost.Asio不仅仅可以用来做网络编程。它还有其他更多的特性,这让它显得更有价值,比如信号量,计时器等等。

下一章我们将深入研究大多数Boost.Asio中用来做网络编程的函数和类。同时我们也会学一些异步编程的诀窍。

时间: 09-22

Boost.Asio c++ 网络编程翻译(6)的相关文章

Boost.Asio c++ 网络编程翻译(14)

保持活动 假如,你需要做下面的操作: io_service service; ip::tcp::socket sock(service); char buff[512]; ... read(sock, buffer(buff)); 在这个例子中,sock和buff的存在时间都必须比read()调用的时间要长.也就是说,在调用read()返回之前,它们都必须有效.这就是你期望的:你传给一个方法的所有参数在参数内部都必须有效.当我们采用异步方式时,事情会变得越复杂. io_service servi

Boost.Asio c++ 网络编程翻译(4)

同步VS异步 首先,异步编程和同步编程是有极大的不同的.在同步编程中,你所有的操作都是顺序执行的,比如从一个socket中读取(请求),然后写入(回应)到socket中.每一个操作操作都是阻塞的.因为操作是阻塞的,所以为了不影响主程序,当读写一个socket时,通常创建一个或多个线程来处理socket的输入/输出.因此,同步的服务端/客户端通常是多线程的. 相反的,异步编程是事件驱动的.你启动了一个操作,但是你不知道它何时会结束:你只是提供一个回调,当操作结束时,它会调用这个API,并返回操作结

Boost.Asio c++ 网络编程翻译(23)

客户端应用中的异步I/O 主流程和同步客户端应用有点类似,不同的是Boost.Asio每次都位于async_read和async_write请求中间. 第一种情况是我在第四章 客户端和服务端 中实现过的.你应该还记得在每个异步操作结束的时候,我都启动另外一个异步操作,这样service.run()方法才不会结束. 为了适应第二种情况,你需要使用下面的代码片段: void on_connect() { do_read(); } void do_read() { async_read(sock_,

A guide to getting started with boost::asio

http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/ 可以多个线程拥有io_service service;  service.run();但是不能一个线程运行多个service.run(); Boost.Asio c++ 网络编程翻译(1) http://blog.csdn.net/mmoaay/article/details/39371939

boost asio 翻译(一)

http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/ 编译环境 boost1.59  vs2015 A guide to getting started with boost::asioboost asio 学习指南 boost::asio是一个使用现代C++方法为开发者提供异步模型的跨平台的c++网络和 底层IO库.目前已经拥有大量用户并成为boost库的一部分 在开始之

C/C++利用Boost::Asio网络库建立自己的Socket服务器

引言 寸光阴,当下我们或许更需要利用现有的知识,应用现有的技术.网络是当前互联网的根本,了解网络便开始显得极其重要.今天我们利用Boost库中Asio部分,浅尝网络服务器.此处不做过于深入的开展,为达成学习目的,只做简单的异步并发服务器. 注意:本篇代码没有直接引用boost等命名空间,为的是新入门Boost的同学能够更好的了解每个参数在boost的具体命名空间位置,有助于更好的理解boost的布局. 版权所有:_OE_,转载请注明出处:http://blog.csdn.net/csnd_ayo

boost asio异步读写网络聊天程序客户端 实例详解

// // chat_client.cpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2013 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 http://ww

Boost.Asio基础(五) 异步编程初探

异步编程 本节深入讨论异步编程将遇到的若干问题.建议多次阅读,以便吃透这一节的内容,这一节是对整个boost.asio来说是非常重要的. 为什么需要异步 如前所述,通常同步编程要比异步编程更简单.同步编程下,我们很容易线性地对问题进行考量,函数A调用完,继续执行B,B执行完,继续执行C,以此类推,相对比较直观.而对于异步编程,假设有5个事件,我们很难知道它们具体的执行顺序,你甚至不知道,它到底会不会被执行. 虽然编写异步的程序,很难,但是依然需要使用这种方法.因为服务器程序需要同时并行的处理大量

网络库crash以及boost asio strand dispath分析

最近在做服务器的稳定性的相关测试,服务器的网络底层使用的是boost asio,然后自己做的二次封装以更好的满足需求. 服务器昨天晚上发现crash了一次,之前测试了将近半个多月,有一次是莫名的退出了,不过由于是新的测试服,忘记将ulimit -c进行修改了,所以没有coredump,这次又发生了. coredump如下: #0 0x0000000000000091 in ?? () #1 0x0000000000459729 in ClientHandler::HandleConnect(cp

谈谈Boost网络编程(2)—— 新系统的设计

写文章之前.我们一般会想要採用何种方式,是"开门见山",还是"疑问式开头".写代码也有些类似.在编码之前我们须要考虑系统总体方案,这也就是各种设计文档的作用.在设计新系统之初,我基本的目的是:保证高效率:保证高扩展性. 效率评价以"任务数/秒"做单位. 因为我的系统仅仅是client,不应该占用太多内存以及CPU.所以内存占用率,CPU使用率也被作为一个硬性指标.那么这里就存在疑问的地方:client有必要採用Boost Asio来做吗?我个人认