基于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 公…

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…

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缓存&…

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

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

Yocto,嵌入式开发者不可不知的强大工具【附资料与活动】

各个嵌入式开发团队出于不同的原因&#xff0c;都希望构建适合自己开发需求的嵌入式系统。Yocto正是这样一个工具&#xff0c;任何一个厂商都可以根据Yocto定制属于自己的系统。 Yocto 是什么 Yocto 是一种伞式项目&#xff0c;侧重于通过开放式嵌入内核&#xff0c;打造嵌入式…

第四次过程性考核

https://gitee.com/liuji1/fourth_process_assessment (一) 问题&#xff1a;使用套接写连接编写一个简单的聊天室程序&#xff0c;客户端主函数放在Client_Main.java文件中&#xff0c;服务器端主函数放在Server_Main.java文件中 (二) 要求&#xff1a; 1.客户端从控制台进行…

劝你不要转行

在知乎收到一个咨询&#xff0c;问题如下您好&#xff0c;想向您请教一些问题。想转行做嵌入式工程师个人基本信息29岁&#xff0c;电子与通信工程专业硕士&#xff0c;毕业后就职于某车企&#xff0c;主要从事类似项目管理一职。去年考入某事业单位&#xff0c;业余时间相对较…

linux下DHCP的安装配置

今天在整理以前的资料的时候&#xff0c;看到了这篇过去积攒的资料&#xff0c;过程详细所以拿来给大家一块分享&#xff0c;同时我也在做&#xff0c;提高一下熟练度。 【实验名称】Linux下DHCP服务的配置与安装【实验拓扑】【实验目标】了解DHCP服务的工作原理&#xff0c;掌…

浅谈一下嵌入式中的强符号和弱符号

__attribute__ 是一个编译器指令&#xff0c;其实是 GNU C 的一种机制&#xff0c;本质是一个编译器的指令&#xff0c;在声明的时候可以提供一些属性&#xff0c;在编译阶段起作用&#xff0c;来做多样化的错误检查和高级优化。用于在 C、C、Objective-C 中修饰变量、函数、参…

POJ_1862 Stripies 【贪心】

一、题面 POJ1862 二、分析 反省一下&#xff0c;自己英语水平着实不行&#xff0c;该题其实就是问若给出若干个这种生物&#xff0c;根据这种体重变换方式&#xff0c;最终合并成一个后&#xff0c;体重最少是多少。根据公式 $m 2\sqrt{m_{1}m_{2}}$ 我们可以发现&#xff0c…

想成为硬件工程师,难不?

有很多朋友经常会问&#xff0c;成为高级嵌入式系统硬件工程师&#xff0c;需要做到哪些呢?那么&#xff0c;我们就先从嵌入式硬件工程师是个什么概念入手。一、如何理解“嵌入式”的概念呢?1、从硬件上&#xff0c;将基于CPU的处围器件&#xff0c;整合到CPU芯片内部&#x…

.Net/C#中Cache的用法

Cache 即高速缓存&#xff0c;使用合理可以提高网站访问速度&#xff0c;减少服务器压力 什么是缓存&#xff1f;Web 应用程序通常都是被多个用户访问。一个Web站点可能存在一个“重量级”的加载&#xff0c;它能够使得站点在访问的时候&#xff0c;拖慢整个服务器。当站点被大…