情景分析
   现已存在一个可用稳定的异步客户端类http_client_base,该类基于boost asio实现了连接服务器,发送请求,获取响应和解析http数据等操作,该类的大致实现框架如下

  1class http_client_base
  2{
  3public:
  4    http_client_base(boost::asio::io_service& io_service)
  5        :resolver_(io_service),socket_(io_service)
  6    { 
  7    }
  8    
  9    void async_connect(const std::string& address,const std::string& port)
 10    {    
 11        boost::asio::ip::tcp::resolver::query query(address, port);
 12        resolver_.async_resolve(query,boost::bind(&http_client::handle_resolve, this,
 13        asio::placeholders::error,asio::placeholders::iterator));
 14    }
 15    
 16    void async_write(const void* data,size_t size,bool in_place=false)
 17    {
 18        if(!in_place){
 19            //do something
 20            asio::async_write(socket_,request_,
 21                            boost::bind(&http_client::handle_write,this,boost::asio::placeholders::error));
 22        }else
 23            asio::async_write(socket_,asio::buffer(data,size),
 24                            boost::bind(&http_client::handle_write,this,boost::asio::placeholders::error));
 25    }
 26    
 27    void async_write_some(const void* data,size_t size,bool in_place=false)
 28    {
 29        if(!in_place){
 30            //do something
 31            boost::asio::async_write(socket_,request_,
 32                                    boost::bind(&http_client::handle_write_some,this,boost::asio::placeholders::error));
 33        }else
 34            boost::asio::async_write(socket_,boost::asio::buffer(data,size),
 35                                    boost::bind(&http_client::handle_write_some,this,boost::asio::placeholders::error));
 36    }
 37
 38private:
 39    void handle_resolve(const boost::system::error_code& e,boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
 40    {
 41        if (!e)
 42            boost::asio::async_connect(socket_, endpoint_iterator,
 43                                    boost::bind(&http_client::handle_connect,this,boost::asio::placeholders::error));
 44        else
 45            onIoError(e);
 46    }
 47    
 48    void handle_connect(const boost::system::error_code& e)
 49    {
 50        if(!e)
 51            onConnect();
 52        else
 53            onIoError(e);
 54    }
 55
 56    void handle_write_some(const boost::system::error_code& e)
 57    {
 58        if(!e)
 59            onWriteSome();
 60        else
 61            onIoError(e);
 62    }
 63
 64    void handle_write(const boost::system::error_code& e)
 65    {
 66        if(!e)
 67            boost::asio::async_read_until(socket_, response_,"\r\n\r\n",
 68                            boost::bind(&http_client::handle_read_header,this,
 69                            boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
 70        else
 71            onIoError(e);
 72    }
 73    
 74    void handle_read_header(const boost::system::error_code& e,size_t bytes_transferred)
 75    {
 76        if(!e){
 77            //do something
 78            boost::asio::async_read(socket_,response_,asio::transfer_at_least(1),
 79                            boost::bind(&http_client::handle_read_content,this,
 80                            boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred);                            
 81        }else
 82            onIoError(e);
 83    }
 84
 85    void handle_read_content(const boost::system::error_code& e,size_t bytes_transferred)
 86    {
 87        if(!e){
 88            //do something
 89            boost::asio::async_read(socket_,response_,asio::transfer_at_least(1),
 90                                boost::bind(&http_client::handle_read_content,this,
 91                                boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
 92        }else
 93            onIoError(e);
 94    }
 95
 96protected:
 97    virtual void onConnect(){}
 98    virtual void onWriteSome(){}
 99    virtual void onIoError(const boost::system::error_code& e){}
100
101private:
102    boost::asio::ip::tcp::socket socket_;
103    boost::asio::ip::tcp::resolver resolver_;
104    boost::asio::streambuf request_;
105    boost::asio::streambuf response_;
106};

显而易见,http_client_base使用tcp::socket作为底层实现,所以数据是非ssl传输的。现因需求变更,为了数据安全要求使用ssl传输。但boost asio中的ssl::stream类接口和tcp::socket有所不同。其实在非ssl和ssl间,不同的只是读写数据的方法,而数据处理逻辑不变,因此为了重用http_client_base的机制框架和对http数据的解析,那么怎么使http_client_base不作大的改动就支持ssl呢?通过研究boost asio源码发现,async_xxx系列自由函数内部要求读写流实现read_some、async_read_some、write_some和async_write_some4个短读写方法。由于tcp::socket已实现短读写而且ssl::stream是tcp::socket的上层,因此只要设计一个抽象的基类流,使之支持read_some、async_some_read、w rite _some和async_write_some即可,而实现使用dynamic_cast转到兄弟基类tcp::socket或ssl::stream,再调用它们对应的同名短读写方法;另外还需要给出获取最底层socket的接口,以支持async_connect和connect方法。因此针对这一设计实现,则要求派生类必须同时从抽象基类和其兄弟基类tcp::socket或ssl::stream继承。

框架实现

  1template<typename T>
  2class boost_socket_base
  3{
  4public:
  5    typedef boost::asio::ssl::stream<T> ssl_socket_base_t;
  6    typedef T socket_base_t;
  7
  8protected:
  9    boost_socket_base()
 10        :tb_(boost::indeterminate)
 11    {
 12    }
 13
 14public:
 15    virtual ~boost_socket_base() {}
 16
 17    ssl_socket_base_t* get_ssl_socket()
 18    {
 19        if(tb_){
 20            BOOST_ASSERT(ss_);        
 21            return ss_;
 22        }else if(!tb_)
 23            return NULL;
 24        else{
 25            if(ss_=dynamic_cast<ssl_socket_base_t*>(this))
 26                tb_ = true;
 27            return ss_;
 28        } 
 29    }
 30
 31    socket_base_t* get_socket()
 32    {
 33        if(!tb_){
 34            BOOST_ASSERT(s_);        
 35            return s_;
 36        }else if(tb_)
 37            return NULL;
 38        else{
 39            if(s_=dynamic_cast<socket_base_t*>(this))
 40                tb_ = false;
 41            return s_;
 42        }
 43    }
 44
 45    void reset()
 46    {    tb_ = boost::indeterminate; }
 47
 48    typename T::lowest_layer_type& lowest_layer()
 49    {
 50        ssl_socket_base_t* p = get_ssl_socket();
 51        if(p) 
 52            return p->lowest_layer();
 53        else
 54            return get_socket()->lowest_layer();
 55    }
 56
 57    template <typename MutableBufferSequence>
 58    std::size_t read_some(const MutableBufferSequence& buffers)
 59    {
 60        ssl_socket_base_t* p = get_ssl_socket();
 61        if(p) 
 62            return p->read_some(buffers);
 63        else
 64            return get_socket()->read_some(buffers);
 65    }
 66    
 67    template <typename MutableBufferSequence>
 68    std::size_t read_some(const MutableBufferSequence& buffers,boost::system::error_code& ec)
 69    {
 70        ssl_socket_base_t* p = get_ssl_socket();
 71        if(p) 
 72            return p->read_some(buffers,ec);
 73        else
 74            return get_socket()->read_some(buffers,ec);
 75    }
 76
 77    template <typename MutableBufferSequence, typename ReadHandler>
 78    void async_read_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
 79    {
 80        ssl_socket_base_t* p = get_ssl_socket();
 81        if(p) 
 82            return p->async_read_some(buffers,handler);
 83        else
 84            return get_socket()->async_read_some(buffers,handler);
 85    }
 86
 87    template <typename ConstBufferSequence>
 88    std::size_t write_some(const ConstBufferSequence& buffers,boost::system::error_code& ec)
 89    {
 90        ssl_socket_base_t* p = get_ssl_socket();
 91        if(p) 
 92            return p->write_some(buffers,ec);
 93        else
 94            return get_socket()->write_some(buffers,ec);
 95    }
 96
 97    template <typename ConstBufferSequence>
 98    std::size_t write_some(const ConstBufferSequence& buffers)
 99    {
100        ssl_socket_base_t* p = get_ssl_socket();
101        if(p) 
102            return p->write_some(buffers);
103        else
104            return get_socket()->write_some(buffers);
105    }
106
107    template <typename MutableBufferSequence, typename ReadHandler>
108    void async_write_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
109    {    
110        ssl_socket_base_t* p = get_ssl_socket();
111        if(p) 
112            return p->async_write_some(buffers,handler);
113        else
114            return get_socket()->async_write_some(buffers,handler);
115    }
116
117private:
118    boost::tribool tb_;
119    union {
120        ssl_socket_base_t* ss_;
121        socket_base_t* s_;
122    };
123};

考虑到dynamic_cast转换的性能开销,因此增加了三态逻辑变量tb_和union指针,tb_表示当前this实际指向的对象类型,初始化为indeterminate,true表示ssl socket对象,使用ss_;false表示普通socket对象,使用s_。这样一来,当且仅当tb_为indeterminate时才dynamic_cast。由于这点优化仅对基类指针操作有效,而对派生对象实无必要,所以tb_和union指针设为私有的;而且基类指针可以指向不同的子类对象,所以增加了reset方法重设tb_为indeterminate状态,保证行为的正确性。

应用改进
   使用boost_socket_base框架后,只须5个地方稍作改动即可。
   1)成员变量 :由原来的boost::asio::ip::tcp改为boost_socket_base<boost_tcp_socket>*类型。

1typedef boost::asio::ip::tcp::socket boost_tcp_socket;
2boost_socket_base<boost_tcp_socket>* socket_;

2)构造函数 :增加boost::asio::ssl::context* ctx参数,默认为NULL,表示不使用ssl。

1http_client_base(boost::asio::io_service& io_service,boost::asio::ssl::context* ctx=NULL)
2    :resolver_(io_service)
3{
4        if(ctx)
5            socket_ = new boost_ssl_socket<boost_tcp_socket>(io_service,*ctx);
6        else
7            socket_ = new boost_socket<boost_tcp_socket>(io_service);
8}

3)握手 处理 :与非ssl不同的是,在连接后需要进行握手,握手成功后才回调onConnect。

 1void handle_connect(const boost::system::error_code& e)
 2{
 3    if(!e){
 4        boost_socket_base<boost_tcp_socket>::ssl_socket_base_t* p = socket_->get_ssl_socket();
 5        if(p)
 6            p->async_handshake(boost::asio::ssl::stream_base::client,boost::bind(&http_client::handle_handshake,
 7                           this,boost::asio::placeholders::error));
 8        else
 9            onConnect();
10    }else
11        onIoError(e);
12}
13void handle_handshake(const boost::system::error_code& e)
14{
15    if(!e)
16        onConnect();
17    else
18        onIoError(e);
19}

4)异步连接 :由于async_connect只接受boost::basic_socket类即最底层的socket作为参数,因此需要调用lowest_layer。

1void handle_resolve(const boost::system::error_code& e,boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
2{
3    if (!e)
4        boost::asio::async_connect(socket_->lowest_layer(), endpoint_iterator,boost::bind(&http_client::handle_connect,this,boost::asio::placeholders::error));
5    else
6        onIoError(e);
7}

5)async_xxx调用 :将参数socet_改为*socket_,例如下。

 1void async_write(const void* data,size_t size,bool in_place=false)
 2{
 3    if(!in_place){
 4        //do something
 5        boost::asio::async_write(*socket_,request_,boost::bind(&http_client::handle_write,this,boost::asio::placeholders::error));
 6    }else
 7        boost::asio::async_write(*socket_,asio::buffer(data,size),boost::bind(&http_client::handle_write,this,boost::asio::placeholders::error));
 8}
 9void handle_write(const boost::system::error_code& e)
10{
11    if(!e)
12        boost::asio::async_read_until(*socket_, response_, "\r\n\r\n",
13                    boost::bind(&http_client::handle_read_header,this,boost::asio::placeholders::error,asio::placeholders::bytes_transferred));
14    else
15        onIoError(e);
16}

基于boost asio实现的支持ssl的通用socket框架相关推荐

  1. Boost:基于boost::asio的延迟udp服务器测试程序

    Boost:基于boost::asio的延迟udp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟udp服务器测 ...

  2. Boost:基于boost::asio的延迟tcp服务器测试程序

    Boost:基于boost::asio的延迟tcp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟tcp服务器测 ...

  3. Boost:基于boost::asio单元测试的测试程序

    Boost:基于boost::asio单元测试的测试程序 实现功能 C++实现代码 实现功能 boost::asio模块,基于boost::asio单元测试的测试程序 C++实现代码 #ifndef ...

  4. Boost:基于boost::asio模块引用计数程序

    Boost:基于boost::asio模块引用计数程序 实现功能 C++实现代码 实现功能 基于boost::asio模块引用计数程序 C++实现代码 #include <boost/asio. ...

  5. 基于boost asio实现sync tcp server通信

    文章目录 一.功能介绍 二.string类型数据交互 2.1 程序源码 2.2 编译&&执行 2.3 程序执行结果 三.byte类型数据交互 3.1 程序源码 3.2 编译&& ...

  6. 基于前端Vue后端.NetCore Web后台管理系统通用开本框架采用前后端分离技术,前端使用vue2.6.0,后端使用.netcore3.1,支持跨平台、多租户

    基于前端Vue后端.NetCore Web后台管理系统通用开本框架采用前后端分离技术,前端使用vue2.6.0,后端使用.netcore3.1,支持跨平台.多租户.支持MySQL/SQLServer/ ...

  7. boost asio 文件服务器,基于boost::asio封装搭建的简单服务器

    经过一天的简单学习,尝试自己写一个简单的服务器,能够实现以下三大回调功能:onConnect onMessage onClose 下面直接贴出代码 1.BaseServer抽象类 BaseServer ...

  8. 基于Boost.Asio的异步通信服务器设计与开发

     boost::asio 通讯服务器实践 1. 开发环境搭建 1.1. Asio准备 万事开头难.对于一个C++的陌生者,编译一个开源的代码并不是一件轻松愉快的事情.为使大家在审阅和检测本代码可使 ...

  9. boost asio 应用方法学(二)——深入框架

    要用好它,就必须先了解它,而且不能停止于表面,必须深入到内部.而了解一件事物,先要了解它的框架,再了解它的细节.了解了框架,我们就有了提纲挈领的认识. 关于 boost asio 框架结构,在其文档中 ...

最新文章

  1. 源码编译安装percona-xtrabackup-2.3.2
  2. Redis配置文件中的三个参数
  3. 附录2:Numpy实例记录
  4. 每日源码分析 - lodash(debounce.js和throttle.js)
  5. Vue004_条件渲染
  6. 微信公众平台如何获得openid
  7. [死亡笔记]某傻逼的错误实况
  8. java碰碰球历险记下载_幼儿园玩球教案碰碰球.doc
  9. UOJRoundPLUS+
  10. 用vuejs如何实现ajax,vuejs使用FormData实现ajax上传图片文件
  11. Java八股系列——Java数据结构
  12. Android异常 Eclipse编译应用时出现 com.android.dx.cf.iface.parseexception
  13. ASP视频教程:SQL语句1
  14. 【数据库】数据库安全性
  15. 定级阿里P7,300道Java面试题帮你全副武装
  16. 各平台电脑开启虚拟化的方法
  17. react + canvas点线动画背景
  18. (转)(图文详细)win 10禁用F1到F12热键/win10 把F1到F12多媒体键转变为功能键
  19. 下一轮人工智能泡沫,或将由消费机器人引发
  20. 计算机桌面怎么突然变大了,电脑屏幕突然变大了怎么办

热门文章

  1. Centos中配置环境变量
  2. 前端测试利器--Browser-Sync启动命令
  3. linux下搭建FTP服务器
  4. MemCached的telnet命令行参数
  5. 走出浮躁的泥沼:浮躁的社会原因 控制好自己的物欲
  6. PostgreSQL的 initdb 源代码分析之二十一
  7. 双硬盘奇怪问题...
  8. 凡事想开,心情不坏~
  9. akshare 布林通道策略
  10. java自动注入注解_Spring自动注解标签@Autowired不能注入xml配置的bean吗?