1. 关于示例代码 chat

先从简单的入手,

在如下路径:boost_1_63_0/libs/asio/example/cpp11/chat中找到chat_server.cpp

查看其成员,

private:
tcp::acceptor acceptor_;
tcp::socket socket_;

仅关注上述两个即可,其它的请自动忽略,在本文中不相关。使用过asio的都知道,io_service绝对不能少

,在本例中由main传入。这次分析代码全部从本例出发,通过逐步查看acceptor_和socket知道asio的工作原理。

正式开工!!

2. acceptor

先来看看例子中的acceptor_的定义,如下:

class tcp
{
public:
typedef basic_socket_acceptor<tcp> acceptor;
// 忽略代码....
}; template <typename Protocol,
typename SocketAcceptorService = socket_acceptor_service<Protocol> >
class basic_socket_acceptor
: public basic_io_object<SocketAcceptorService>,
public socket_base
{
//忽略代码....
};

acceptor是一个继承自basic_io_object和socket_base,同时具有模板参数

Protocol和SocketAcceptorService的类。Protocol即本例中的tcp。

搜索tcp.hpp所在路径,会发现udp.hpp。两个文件同在ip这个路径下面,表示要使用的内容是属于

哪种协议。对比两个类的定义,能够知道仅在protocol()函数返回的值IPPROTO_UDP和IPPROTO_TCP不同。

2.1 acceptor的构造

chat_server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint)
: acceptor_(io_service, endpoint),
socket_(io_service)

在构造中,传入了两个参数io_service和endpoint,reuse_addr标记是否开启地址复用。

basic_socket_acceptor(boost::asio::io_service& io_service,
const endpoint_type& endpoint, bool reuse_addr = true)
: basic_io_object<SocketAcceptorService>(io_service)
{
boost::system::error_code ec;
1. const protocol_type protocol = endpoint.protocol();
2. this->get_service().open(this->get_implementation(), protocol, ec);
boost::asio::detail::throw_error(ec, "open");
if (reuse_addr)
{
this->get_service().set_option(this->get_implementation(),
socket_base::reuse_address(true), ec);
boost::asio::detail::throw_error(ec, "set_option");
}
this->get_service().bind(this->get_implementation(), endpoint, ec);
boost::asio::detail::throw_error(ec, "bind");
this->get_service().listen(this->get_implementation(),
socket_base::max_connections, ec);
boost::asio::detail::throw_error(ec, "listen");
}

line1: endpoint 提供了一个函数protocol() 返回的类型是protocol_type,定义如下:

typedef Protocol protocol_type;

其它的位置暂时没有相关的内容了,所以为了避免在开始就把摊子铺的太开,可以暂时不鸟endpoint的细节,

仅知道在basic_socket_acceptor中,它帮助类识别当前是什么协议(tcp/udp).

line2: 函数中open/set_option/bind/listen是相似操作。get_service隐藏了关键的细节,而在boost的调性中,this表明“我要啃老了”。

2.2 被啃老的basic_io_object

在chapter 2.0中,basic_io_object的模板参数传入了类型,SocketAcceptorService,当然啦在本例中即默认参数

socket_acceptor_service。

template <typename IoObjectService>
class basic_io_object
{
public:
/// The type of the service that will be used to provide I/O operations.
typedef IoObjectService service_type; /// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;

到这里已经不用向下看了,在chapter2.1中使用的操作都集中在了socket_acceptor_service中。

在asio中,basic_io_object提供了*_acceptor 和 *acceptor_service的衔接桥梁,明确了接口暴露和功能实现的区分方式。

类似的映射关系还存在于如下:

basic_deadline_timer -> deadline_timer_service
basic_serial_port -> serial_port_service
basic_signal_set -> signal_set_service

由于_acceptor_service的实现过于复杂包含很多作为acceptor不需要知道的细节,其实看到这里通过命名也可以知道,

_acceptor_service具有io_service和acceptor的衔接者身份。

前方高能!!!!

2.3 socket_acceptor_service

从上文中可以知道acceptor的功能实现都集中于其对应的acceptor_service中,在2.1中还留下一个坑

this->get_implementation()到底是个啥子?

typedef detail::reactive_socket_service<Protocol> service_impl_type;
typedef typename service_impl_type::implementation_type implementation_type;

reactive_socket_service提供了我们最终的类型定义:

struct base_implementation_type
{
// The native socket representation.
socket_type socket_; // The current state of the socket.
socket_ops::state_type state_; // Per-descriptor data used by the reactor.
reactor::per_descriptor_data reactor_data_;
};

终于出现了和2.1节函数名称相符合的参数了,socket_type(int)。

io_service在本类中作为reactive_socket_service的构造函数参数,reactive_socket_service啃老reactive_socket_service_base

reactive_socket_service_base::reactive_socket_service_base(
boost::asio::io_service& io_service)
: reactor_(use_service<reactor>(io_service))
{
reactor_.init_task();
}

终于出现能和io_service扯上关系的地方了。查看reactor_

#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
typedef class null_reactor reactor;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef class select_reactor reactor;
#elif defined(BOOST_ASIO_HAS_EPOLL)
typedef class epoll_reactor reactor;
#elif defined(BOOST_ASIO_HAS_KQUEUE)
typedef class kqueue_reactor reactor;
#elif defined(BOOST_ASIO_HAS_DEV_POLL)
typedef class dev_poll_reactor reactor;
#else
typedef class select_reactor reactor;
#endif

linux下当然要关心epoll_reactor,惊喜啊,原来关于epoll操作的也出现在这里了,epoll_reactor就是我们要

找的关键操作。

void epoll_reactor::init_task()
{
io_service_.init_task();
}

调用io_service的init_task, 经过复杂的过程终于,在这里又绕回了io_service(上帝)。这里的io_service实际是

task_io_service。

3. 小结

本文从char_server的acceptor出发,通过逐步代码逐步查看,从关键操作中,逐步找到关于系统操作的封装(epoll_reactor)及如何使acceptor和io_service产生联系。basic_io_object充当接耦的角色,将实现细节进行隐藏。

boost.asio源码阅读(1) - 从chat_server开始的更多相关文章

  1. boost.asio源码阅读(2) - task_io_service

    1.0 task_io_service 在boost.asio源码阅读(1)中,代码已经查看到task_io_service中. 具体的操作调用void task_io_service::init_t ...

  2. boost.asio源码剖析(一) ---- 前 言

    * 前言 源码之前,了无秘密.                                                       ——侯捷 Boost库是一个可移植.提供源代码的C++库,作 ...

  3. boost.asio源码剖析(三) ---- 流程分析

    * 常见流程分析之一(Tcp异步连接) 我们用一个简单的demo分析Tcp异步连接的流程: #include <iostream> #include <boost/asio.hpp& ...

  4. boost.asio源码剖析(五) ---- 泛型与面向对象的完美结合

    有人说C++是带类的C:有人说C++是面向对象编程语言:有人说C++是面向过程与面向对象结合的语言.类似的评论网上有很多,虽然正确,却片面,是断章取义之言. C++是实践的产物,C++并没有为了成为某 ...

  5. boost.asio源码剖析(四) ---- asio中的泛型概念(concepts)

    * Protocol(通信协议) Protocol,是asio在网络编程方面最重要的一个concept.在第一章中的levelX类图中可以看到,所有提供网络相关功能的服务和I/O对象都需要Protoc ...

  6. boost.asio源码剖析

    一. 前 言二. 架构浅析三. 流程分析     * 常见流程分析之一(Tcp异步连接)      * 常见流程分析之二(Tcp异步接受连接)      * 常见流程分析之三(Tcp异步读写数据)   ...

  7. boost.asio源码剖析(二) ---- 架构浅析

    * 架构浅析 先来看一下asio的0层的组件图.                     (图1.0) io_object是I/O对象的集合,其中包含大家所熟悉的socket.deadline_tim ...

  8. FreeCAD源码阅读笔记

    本文目标在于记录在FreeCAD源码阅读中了解到的一些东西. FreeCAD编译 FreeCAD源码的编译最好使用官方提供的LibPack,否则第三方库难以找全,找到之后还需要自己编译,此外还不知道C ...

  9. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

随机推荐

  1. OpenCV 3.2正式发布啦

    2016年12月23号OpenCV社区宣布了OpenCV3.2版本正式发布,这个是在OpenCV3.1版本发布一年以后再次升级.在3.2版本中有总数超过数千个的改进与修正,是OpenCV3.x系列中最 ...

  2. 自定义滚动条Js简版

    <!DOCTYPE html><html><head><meta charset="UTF-8"><title>自定义滚 ...

  3. Android 友盟分享详细集成过程及所遇问题解决

    最近项目需要针对微信.朋友圈.QQ.QQ空间集成友盟分享的功能,说实话,我也是第一次做,期间碰到过很多问题,这篇随笔就来写一下我是怎么集成友盟分享的,还有碰到哪些问题,都是怎样解决的! 其实集成友盟并 ...

  4. 面向UI编程:ui.js 1.0 粗糙版本发布,分布式开发+容器化+组件化+配置化框架,从无到有的艰难创造

    时隔第一次被UI思路激励,到现在1.0的粗糙版本发布,掐指一算整整半年了.半年之间,有些细节不断推翻重做,再推翻再重做.时隔今日,终于能先出来个东西了,这个版本很粗糙,主体功能大概能实现了,但是还是有 ...

  5. 构建自动化前端样式回归测试——BackstopJS篇

    在使用scss和less开发的时候,遇到过一件很有趣的事,因为网站需要支持响应式,就开了一个响应式样式框架,简单的几百行scss代码,居然生成了近100KB的css代码,因此决定重构这个样式库.而重构 ...

  6. java udp (使用类调用双通信)1

    项目需要就使用了UDP通信,做了java的双方通信,其实代码还是来自之前的udp学习代码,自己加了注释,并且优化的使用类来封装关于通信类库的使用代码 目的是为了在安卓项目中使用时,可以通过实例化,调用 ...

  7. Angular2 + Webpack项目搭建Demo

    本文将从头开始编写实际的代码来完成一个angular2的demo. 题外话是其实angular2官网的快速开始项目已经很酷炫了,但其侧重快速二字,只够拿来练习玩耍,倒是github上确实已经有了一些不 ...

  8. 【前端】:Dom

    前言: 昨天写了篇关于JavaScript的,今天写篇Dom的(插入4个实例),写完之后感觉知识点还不少~ 内容当然会用到[前端]:JavaScript的知识.下篇博客会写关于jQuery~~ 一.D ...

  9. JSON - 使用cJSON 解析Qt通过UDP发送的JSON数据

    1,cJSON支持在C程序中创建和解析JSON数据,其提供多种方法供C程序使用,最直接的是将cJSON.c和cJSON.h加入到C工程中,源代码:https://github.com/DaveGamb ...

  10. Smarty3配置及入门语法

    一.Smarty3配置 下载Smarty文件 在Smarty的官方网站下载Smarty文件,解压下载到的Smarty文件,Smarty的库文件就在libs文件夹中. 我使用的PHP调试环境的程序集成包 ...