【Boost】boost库asio详解3——io_service作为work pool
无论如何使用,都能感觉到使用boost.asio实现服务器,不仅是一件非常轻松的事,而且代码很漂亮,逻辑也相当清晰,这点上很不同于ACE。
使用io_service作为处理工作的work pool,可以看到,就是通过io_service.post投递一个Handler到io_service的队列,Handler在这个io_service.run内部得到执行,有可能你会发现,io_services.dispatch的接口也和io_service.post一样,但不同的是它是直接调用而不是经过push到队列然后在io_services.run中执行,而在这个示例当中,显然我们需要把工作交到另一个线程去完成,这样才不会影响网络接收线程池的工作以达到高效率的接收数据,这种设计与前面的netsever其实相同,这就是典型的Half Sync/Half Async。二者的区别就是netsever自己实现了工作队列,而不是直接使用io_service,这种设计实际上在win下是使用了iocp作为工作队列。
不过我更倾向于前一种设计,因为那样做,代码一切都在自己的掌握中,而io_service则是经过许多封装代码,并且本身设计只是用于处理网络完成事件的。
无论如何使用,都能感觉到使用boost.asio实现服务器,不仅是一件非常轻松的事,而且代码很漂亮,逻辑也相当清晰,这点上很不同于ACE。
- #include <stdio.h>
- #include <cstdlib>
- #include <iostream>
- #include <boost/thread.hpp>
- #include <boost/aligned_storage.hpp>
- #include <boost/array.hpp>
- #include <boost/bind.hpp>
- #include <boost/enable_shared_from_this.hpp>
- #include <boost/noncopyable.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/asio.hpp>
- using boost::asio::ip::tcp;
- class handler_allocator
- : private boost::noncopyable
- {
- public:
- handler_allocator()
- : in_use_(false)
- {
- }
- void* allocate(std::size_t size)
- {
- if (!in_use_ && size < storage_.size)
- {
- in_use_ = true;
- return storage_.address();
- }
- else
- {
- return ::operator new(size);
- }
- }
- void deallocate(void* pointer)
- {
- if (pointer == storage_.address())
- {
- in_use_ = false;
- }
- else
- {
- ::operator delete(pointer);
- }
- }
- private:
- // Storage space used for handler-based custom memory allocation.
- boost::aligned_storage<1024> storage_;
- // Whether the handler-based custom allocation storage has been used.
- bool in_use_;
- };
- template <typename Handler>
- class custom_alloc_handler
- {
- public:
- custom_alloc_handler(handler_allocator& a, Handler h)
- : allocator_(a),
- handler_(h)
- {
- }
- template <typename Arg1>
- void operator()(Arg1 arg1)
- {
- handler_(arg1);
- }
- template <typename Arg1, typename Arg2>
- void operator()(Arg1 arg1, Arg2 arg2)
- {
- handler_(arg1, arg2);
- }
- friend void* asio_handler_allocate(std::size_t size,
- custom_alloc_handler<Handler>* this_handler)
- {
- return this_handler->allocator_.allocate(size);
- }
- friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
- custom_alloc_handler<Handler>* this_handler)
- {
- this_handler->allocator_.deallocate(pointer);
- }
- private:
- handler_allocator& allocator_;
- Handler handler_;
- };
- // Helper function to wrap a handler object to add custom allocation.
- template <typename Handler>
- inline custom_alloc_handler<Handler> make_custom_alloc_handler(
- handler_allocator& a, Handler h)
- {
- return custom_alloc_handler<Handler>(a, h);
- }
- /// A pool of io_service objects.
- class io_service_pool
- : private boost::noncopyable
- {
- public:
- /// Construct the io_service pool.
- explicit io_service_pool(std::size_t pool_size) : next_io_service_(0)
- {
- if (pool_size == 0)
- throw std::runtime_error("io_service_pool size is 0");
- // Give all the io_services work to do so that their run() functions will not
- // exit until they are explicitly stopped.
- for (std::size_t i = 0; i < pool_size; ++i)
- {
- io_service_ptr io_service(new boost::asio::io_service);
- work_ptr work(new boost::asio::io_service::work(*io_service));
- io_services_.push_back(io_service);
- work_.push_back(work);
- }
- }
- // Run all io_service objects in the pool.
- void run()
- {
- // Create a pool of threads to run all of the io_services.
- std::vector<boost::shared_ptr<boost::thread> > threads;
- for (std::size_t i = 0; i < io_services_.size(); ++i)
- {
- boost::shared_ptr<boost::thread> thread(new boost::thread(
- boost::bind(&boost::asio::io_service::run, io_services_[i])));
- threads.push_back(thread);
- }
- // Wait for all threads in the pool to exit.
- for (std::size_t i = 0; i < threads.size(); ++i)
- threads[i]->join();
- }
- // Stop all io_service objects in the pool.
- void stop()
- {
- // Explicitly stop all io_services.
- for (std::size_t i = 0; i < io_services_.size(); ++i)
- io_services_[i]->stop();
- }
- // Get an io_service to use.
- boost::asio::io_service& get_io_service()
- {
- // Use a round-robin scheme to choose the next io_service to use.
- boost::asio::io_service& io_service = *io_services_[next_io_service_];
- ++next_io_service_;
- if (next_io_service_ == io_services_.size())
- next_io_service_ = 0;
- return io_service;
- }
- private:
- typedef boost::shared_ptr<boost::asio::io_service> io_service_ptr;
- typedef boost::shared_ptr<boost::asio::io_service::work> work_ptr;
- /// The pool of io_services.
- std::vector<io_service_ptr> io_services_;
- /// The work that keeps the io_services running.
- std::vector<work_ptr> work_;
- /// The next io_service to use for a connection.
- std::size_t next_io_service_;
- };
- class session
- : public boost::enable_shared_from_this<session>
- {
- public:
- session(boost::asio::io_service& work_service
- , boost::asio::io_service& io_service)
- : socket_(io_service)
- , io_work_service(work_service)
- {
- }
- tcp::socket& socket()
- {
- return socket_;
- }
- void start()
- {
- socket_.async_read_some(boost::asio::buffer(data_),
- make_custom_alloc_handler(allocator_,
- boost::bind(&session::handle_read,
- shared_from_this(),
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
- }
- void handle_read(const boost::system::error_code& error,
- size_t bytes_transferred)
- {
- if (!error)
- {
- boost::shared_ptr<std::vector<char> > buf(new std::vector<char>);
- buf->resize(bytes_transferred);
- std::copy(data_.begin(), data_.begin() + bytes_transferred, buf->begin());
- io_work_service.post(boost::bind(&session::on_receive
- , shared_from_this(), buf, bytes_transferred));
- socket_.async_read_some(boost::asio::buffer(data_),
- make_custom_alloc_handler(allocator_,
- boost::bind(&session::handle_read,
- shared_from_this(),
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
- }
- }
- void handle_write(const boost::system::error_code& error)
- {
- if (!error)
- {
- }
- }
- void on_receive(boost::shared_ptr<std::vector<char> > buffers
- , size_t bytes_transferred)
- {
- char* data_stream = &(*buffers->begin());
- // in here finish the work.
- std::cout << "receive :" << bytes_transferred << " bytes." <<
- "message :" << data_stream << std::endl;
- }
- private:
- // The io_service used to finish the work.
- boost::asio::io_service& io_work_service;
- // The socket used to communicate with the client.
- tcp::socket socket_;
- // Buffer used to store data received from the client.
- boost::array<char, 1024> data_;
- // The allocator to use for handler-based custom memory allocation.
- handler_allocator allocator_;
- };
- typedef boost::shared_ptr<session> session_ptr;
- class server
- {
- public:
- server(short port, std::size_t io_service_pool_size)
- : io_service_pool_(io_service_pool_size)
- , io_service_work_pool_(io_service_pool_size)
- , acceptor_(io_service_pool_.get_io_service(), tcp::endpoint(tcp::v4(), port))
- {
- session_ptr new_session(new session(io_service_work_pool_.get_io_service()
- , io_service_pool_.get_io_service()));
- acceptor_.async_accept(new_session->socket(),
- boost::bind(&server::handle_accept, this, new_session,
- boost::asio::placeholders::error));
- }
- void handle_accept(session_ptr new_session,
- const boost::system::error_code& error)
- {
- if (!error)
- {
- new_session->start();
- new_session.reset(new session(io_service_work_pool_.get_io_service()
- , io_service_pool_.get_io_service()));
- acceptor_.async_accept(new_session->socket(),
- boost::bind(&server::handle_accept, this, new_session,
- boost::asio::placeholders::error));
- }
- }
- void run()
- {
- io_thread_.reset(new boost::thread(boost::bind(&io_service_pool::run
- , &io_service_pool_)));
- work_thread_.reset(new boost::thread(boost::bind(&io_service_pool::run
- , &io_service_work_pool_)));
- }
- void stop()
- {
- io_service_pool_.stop();
- io_service_work_pool_.stop();
- io_thread_->join();
- work_thread_->join();
- }
- private:
- boost::shared_ptr<boost::thread> io_thread_;
- boost::shared_ptr<boost::thread> work_thread_;
- io_service_pool io_service_pool_;
- io_service_pool io_service_work_pool_;
- tcp::acceptor acceptor_;
- };
- int main(int argc, char* argv[])
- {
- try
- {
- if (argc != 2)
- {
- std::cerr << "Usage: server <port>/n";
- return 1;
- }
- using namespace std; // For atoi.
- server s(atoi(argv[1]), 10);
- s.run();
- getchar();
- s.stop();
- }
- catch (std::exception& e)
- {
- std::cerr << "Exception: " << e.what() << "/n";
- }
- return 0;
- }
【Boost】boost库asio详解3——io_service作为work pool的更多相关文章
- 【Boost】boost库asio详解2——io_service::run函数无任务时退出的问题
io_service::work类可以使io_service::run函数在没有任务的时候仍然不返回,直至work对象被销毁. void test_asio_nowork() { boost::asi ...
- boost库asio详解1——strand与io_service区别
namespace { // strand提供串行执行, 能够保证线程安全, 同时被post或dispatch的方法, 不会被并发的执行. // io_service不能保证线程安全 boost::a ...
- boost库asio详解8——几个TCP的简单例子
摘于boost官网的几个例子, 做了点小修改, 笔记之. 同步客户端 void test_asio_synclient() { typedef boost::asio::io_service IoSe ...
- 【Boost】boost库asio详解5——resolver与endpoint使用说明
tcp::resolver一般和tcp::resolver::query结合用,通过query这个词顾名思义就知道它是用来查询socket的相应信息,一般而言我们关心socket的东东有address ...
- Python爬虫之selenium库使用详解
Python爬虫之selenium库使用详解 本章内容如下: 什么是Selenium selenium基本使用 声明浏览器对象 访问页面 查找元素 多个元素查找 元素交互操作 交互动作 执行JavaS ...
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) 前面 ...
- boost/config.hpp文件详解
简要概述 今天突发奇想想看一下boost/config.hpp的内部实现,以及他有哪些功能. 这个头文件都有一个类似的结构,先包含一个头文件,假设为头文件1,然后包含这个头文 件中定义的宏.对于头文件 ...
- 标准I/O库(详解)(Standard I/O Library)
文章转自:https://www.cnblogs.com/kingcat/archive/2012/05/09/2491847.html 自己在学习中,对此原文的基础之上进行补充. 什么是缓冲区 缓冲 ...
- STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解)
介绍 FwLib_STC8 是一个针对STC8G, STC8H系列MCU的C语言封装库, 适用于基于这些MCU的快速原型验证. 项目地址: Gitee FwLib_STC8 镜像地址: GitHub ...
随机推荐
- Odoo calendar 提醒器
Odoo calendar 提供了一个提醒功能,它包含邮件通知以及web client弹窗功能 创建日历事件的时候,可以设置提醒器 Meeting [ calendar.event ] ...
- Android 大众点评的接入
这里介绍的是大众点评的团购中的一个接口.就是全部团购信息,其它的接口的实现是大同小异的. 首先,登录大众点评的开发平台->大众点评 . 然后获取到自己的应用的appkey和secret.这个是 ...
- Ansible 汇总
不错的博客:https://www.cnblogs.com/EWWE/p/8146083.html 修改文件权限: 首先需要 vi /etc/ansible/hosts (用pip install, ...
- Kubernetes对象之Pod
系列目录 Pod是Kubernetes调度的最小单元.一个Pod可以包含一个或多个容器,因此它可以被看作是内部容器的逻辑宿主机.Pod的设计理念是为了支持多个容器在一个Pod中共享网络和文件系统 因此 ...
- Kubernetes对象之Service
系列目录 通过ReplicaSet来创建一组Pod来提供具有高可用性的服务.虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题: Pod IP仅仅是集群内可见的虚拟IP,外部无法访问. ...
- 生产制造追溯系统-IQC来料检验
前言 相信大家都知道,任何一家工厂都有自己的仓库,用来存储采购回来的物料,那么在供应商将我们采购的物料送到工厂之后,我们都需要一个检验动作,也就是今天要说的===>IQC来料检验,这个检验动作是 ...
- python发送post请求上传文件,无法解析上传的文件
前言 近日,在做接口测试时遇到一个奇葩的问题. 使用post请求直接通过接口上传文件,无法识别文件. 遇到的问题 以下是抓包得到的信息: 以上请求是通过Postman直接发送请求的. 在这里可以看到消 ...
- 图像滤镜艺术---PS图层混合模式之明度模式
本文将介绍PS图层混合模式中比較复杂 的"明度"模式的算法原理及代码实现内容. 说到PS的图层混合模式,计算公式都有,详细代码实现也能找到,可是,都没有完整介绍全部图层混合模式的代 ...
- Linux中ctrl+z 、ctrl+c、 ctrl+d差别
ctrl+c,ctrl+d,ctrl+z在linux程序中意义和差别 ctrl+c和ctrl+z都是中断命令,可是他们的作用却不一样. ctrl+c是强制中断程序的运行,,进程已经终止. ct ...
- iOS开发之──传感器使用
本文转载至 http://mobile.51cto.com/iphone-423219.htm 在实际的应用开发中,会用到传感器,下面首先介绍一下iphone4的传感器,然后对一些传感器的开发的API ...