基于boost asio实现的支持ssl的通用socket框架

情景分析
   现已存在一个可用稳定的异步客户端类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}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463950.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#创建简单的验证码

首先&#xff0c;创建一个CLASS类&#xff0c;然后需要add Reference的方式添加 System.Drawing&#xff08;画画的类&#xff09; 方法代码如下&#xff1a; 1/**//**//**//// <summary> 2 /// 定义显示的随机字符 3 /// </summary> 4 /// &…

昨天的事情想说一下

发那篇文章的目的昨天发文章之后&#xff0c;我的一个好朋友微信找我&#xff0c;跟我说了很多关于文章的事情&#xff0c;所以&#xff0c;我自己也思考了许多。关于泄愤这个事情&#xff0c;我还是挺想说的。可能很多人看到了一个不好的东西&#xff0c;然后网上发发这个&…

Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))...

题目链接&#xff1a; https://codeforces.com/contest/1093/problem/G 题目&#xff1a; 题意&#xff1a; 在k维空间中有n个点&#xff0c;每次给你两种操作&#xff0c;一种是将某一个点的坐标改为另一个坐标&#xff0c;一种操作是查询[l,r]中曼哈顿距离最大的两个点的最大…

poj 3342

概率dp&#xff0c;不解释。 View Code #include<iostream>#include<map>#include<cstdio>#include<vector>using namespace std;const int maxn201;int dp[210][2];vector<int>edge[maxn];void dfs(int u,int p){int i,j; dp[u][1]1;dp[u][…

最全是一次I2C总结

博主将 I2C spec 文章总结为一篇&#xff0c;目录如下I2C Introduction I2C Architecture I2C Transfer I2C Synchronization And Arbitration I2C Hs-mode1、I2C Introduction1、I2C 历史I2C&#xff1a;Inter-Integrated Circuit&#xff0c;集成电路总线。I2C 是 Philips 公…

Interesting Finds: 2008.03.24

.NET: C#正则表达式整理备忘 谈谈volatile变量 Other: PTOM: The Open Closed Principle Calculating pi with C# - Calculate PI using C# Regular Expression Workbench - a free and opensource option for RegexBuddy 转载于:https://www.cnblogs.com/gOODiDEA/archive/2…

如何利用openSsl来计算一个文件的md5值?

openssl环境的配置&#xff0c; 我就不再说了。在本文中&#xff0c; 我们来讨论一个文件的md5值&#xff0c; 废话少说&#xff0c; 直接给大家代码&#xff0c; 上点干货&#xff1a; [cpp] view plaincopy #include <iostream> #include <openssl/md5.h> // 如…

qs文档翻译

安装&#xff1a; npm install qs --save-dev 基本用法&#xff1a; 1 let qs require(qs);2 let assert require(assert);3 4 5 //qs.parse(ac)将字符串等式转换为对象6 let obj qs.parse(ac);7 console.log(obj)//{a:c}8 9 //qs.stringify(obj)将对象转化为字符串等式 10 …

Lync Server 2010标准版系列PART6:启用Lync

在我们花费了众多的精力和时间之后&#xff0c;我们终于完成了Lync Server标准版的搭建&#xff0c;接下来当然是为我们AD中的用户启用Lync&#xff0c;来看下我们的部署成果。首先我们需要在AD中创建两个帐户&#xff0c;这样便于我们后期的测试&#xff0c;在DC上打开AD用户和…

8位MCU跑RTOS有没有意义?

相信大多数人在学习单片机的时候&#xff0c;都是从最基本的8位MCU开始的。一般来说&#xff0c;8位单片机最常见的是三个系列是&#xff1a;51系列、AVR系列、PIC系列。而前段时间&#xff0c;群里讨论了一个问题&#xff1a;在51单片机上跑RTOS有没有意义&#xff1f;关于这个…

ViewState机制由浅入深1

1 ViewState机制是什么&#xff1f; ViewState机制是asp.net中对同一个Page的多次请求&#xff08;PostBack&#xff09;之间维持Page及控件状态的一种机制。在WebForm中每次请求完&#xff0c;Page对象都会被释放&#xff0c;对同一个Page的多次请求之间的状态信息&am…

关于bc中小数点length,scale,(())以及进制转换

这是我在codewar上遇到的一个题&#xff0c;我用我自己的方法做出了解答&#xff0c;如下&#xff1a; 1 #!/bin/bash2 3 distanceecho "$1*10000"|bc|cut -d"." -f14 a05 n16 7 if [ $distance -le 0 ];then8 echo None9 else 10 while [ $n -lt $di…

利用openssl来计算sha1, sha224, sha256, sha384, sha512

转载&#xff1a;http://blog.csdn.net/stpeace/article/details/42371079 利用openssl来计算sha1, sha224, sha256, sha384, sha512&#xff0c;前提是已经配置了openssl的环境&#xff1a; 代码如下&#xff1a; [cpp] view plaincopy #include <iostream> #include…

WCF简单教程(6) 单向与双向通讯

第六篇&#xff1a;单向与双向通讯 项目开发中我们时常会遇到需要异步调用的问题&#xff0c;有时忽略服务端的返回值&#xff0c;有时希望服务端在需要的时候回调&#xff0c;今天就来看看在WCF中如何实现。 先看不需要服务端返回值的单向调用&#xff0c;老规矩&#xff0c;直…

5V串口接3.3V单片机串口怎么搞?

写在前面&#xff1a;两个单片机由于电平不同&#xff0c;串口通信可能会失败&#xff0c;这时候需要通过电平转换电路来解决&#xff0c;本文给出了两种方法&#xff0c;一种是通过三极管搭建&#xff0c;另一种是MOS管搭建&#xff0c;在硬件工程师的笔试中也经常会出现这样的…

Django之缓存、信号和图片验证码

一、 缓存 1、 介绍 缓存通俗来说&#xff1a;就是把数据先保存在某个地方&#xff0c;下次再读取的时候不用再去原位置读取&#xff0c;让访问速度更快。 缓存机制图解 2、Django中提供了6种缓存方式 1. 开发调试   2. 内存   3. 文件   4. 数据库   5. Memcache缓存&…

利用openssl来计算sha256哈希值

先配置openssl, 我就不再赘述了&#xff0c; 直接给出代码&#xff1a; [cpp] view plaincopy #include <iostream> #include <openssl/sha.h> // 如果你直接拷贝我的程序运行&#xff0c; 那注定找不到sha.h #pragma comment(lib, "libeay32.lib") …

CuteEditor6.0使用配置心得体会(转)

CuteEditor是一款功能非常强大&#xff0c;支持图片上传、文件下载和word类似的文字编辑器。并且Vs2003和Vs2005都可以适用。对于新闻发布系统和博客之类的系统&#xff0c;是非常的方便的。对一个刚接触这款编辑器的朋友来说或许会遇到和我一样的许多问题&#xff0c;现在我就…

这焊接技术在班里排名第一没问题吧?

晚上和朋友讨论PCB LAYOUT&#xff0c;然后自己也动手起来了&#xff0c;刚好看到宇哥的一篇焊接的文章&#xff0c;这焊接技术这么厉害的人&#xff0c;layout那不得是吊炸天啊。作者&#xff1a;晓宇&#xff0c;排版&#xff1a;晓宇微信公众号&#xff1a;芯片之家&#xf…

html字符串生成器源代码

#-*-coding:utf-8-*-#-*-coding:big5-*-#-*-coding:cp936-*-import Tkinterimport tkFileDialogimport osimport tkMessageBoximport shutilurlnew""#文件打开def manipuOpen(): url tkFileDialog.askopenfilename(title 打开html文件, #创建打开文件对话框…