基于boost asio实现的支持ssl的通用socket框架
情景分析
现已存在一个可用稳定的异步客户端类http_client_base,该类基于boost asio实现了连接服务器,发送请求,获取响应和解析http数据等操作,该类的大致实现框架如下
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继承。
框架实现
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>*类型。
2boost_socket_base<boost_tcp_socket>* socket_;
2)构造函数 :增加boost::asio::ssl::context* ctx参数,默认为NULL,表示不使用ssl。
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。
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。
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_,例如下。
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框架相关推荐
- Boost:基于boost::asio的延迟udp服务器测试程序
Boost:基于boost::asio的延迟udp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟udp服务器测 ...
- Boost:基于boost::asio的延迟tcp服务器测试程序
Boost:基于boost::asio的延迟tcp服务器测试程序 实现功能 C++实现代码 客户端源码 服务端源码 实现功能 boost::asio模块,基于boost::asio的延迟tcp服务器测 ...
- Boost:基于boost::asio单元测试的测试程序
Boost:基于boost::asio单元测试的测试程序 实现功能 C++实现代码 实现功能 boost::asio模块,基于boost::asio单元测试的测试程序 C++实现代码 #ifndef ...
- Boost:基于boost::asio模块引用计数程序
Boost:基于boost::asio模块引用计数程序 实现功能 C++实现代码 实现功能 基于boost::asio模块引用计数程序 C++实现代码 #include <boost/asio. ...
- 基于boost asio实现sync tcp server通信
文章目录 一.功能介绍 二.string类型数据交互 2.1 程序源码 2.2 编译&&执行 2.3 程序执行结果 三.byte类型数据交互 3.1 程序源码 3.2 编译&& ...
- 基于前端Vue后端.NetCore Web后台管理系统通用开本框架采用前后端分离技术,前端使用vue2.6.0,后端使用.netcore3.1,支持跨平台、多租户
基于前端Vue后端.NetCore Web后台管理系统通用开本框架采用前后端分离技术,前端使用vue2.6.0,后端使用.netcore3.1,支持跨平台.多租户.支持MySQL/SQLServer/ ...
- boost asio 文件服务器,基于boost::asio封装搭建的简单服务器
经过一天的简单学习,尝试自己写一个简单的服务器,能够实现以下三大回调功能:onConnect onMessage onClose 下面直接贴出代码 1.BaseServer抽象类 BaseServer ...
- 基于Boost.Asio的异步通信服务器设计与开发
boost::asio 通讯服务器实践 1. 开发环境搭建 1.1. Asio准备 万事开头难.对于一个C++的陌生者,编译一个开源的代码并不是一件轻松愉快的事情.为使大家在审阅和检测本代码可使 ...
- boost asio 应用方法学(二)——深入框架
要用好它,就必须先了解它,而且不能停止于表面,必须深入到内部.而了解一件事物,先要了解它的框架,再了解它的细节.了解了框架,我们就有了提纲挈领的认识. 关于 boost asio 框架结构,在其文档中 ...
最新文章
- 源码编译安装percona-xtrabackup-2.3.2
- Redis配置文件中的三个参数
- 附录2:Numpy实例记录
- 每日源码分析 - lodash(debounce.js和throttle.js)
- Vue004_条件渲染
- 微信公众平台如何获得openid
- [死亡笔记]某傻逼的错误实况
- java碰碰球历险记下载_幼儿园玩球教案碰碰球.doc
- UOJRoundPLUS+
- 用vuejs如何实现ajax,vuejs使用FormData实现ajax上传图片文件
- Java八股系列——Java数据结构
- Android异常 Eclipse编译应用时出现 com.android.dx.cf.iface.parseexception
- ASP视频教程:SQL语句1
- 【数据库】数据库安全性
- 定级阿里P7,300道Java面试题帮你全副武装
- 各平台电脑开启虚拟化的方法
- react + canvas点线动画背景
- (转)(图文详细)win 10禁用F1到F12热键/win10 把F1到F12多媒体键转变为功能键
- 下一轮人工智能泡沫,或将由消费机器人引发
- 计算机桌面怎么突然变大了,电脑屏幕突然变大了怎么办