基于boost asio实现的ssl socket框架
情景分析
现已存在一个可用稳定的异步客户端类http_client_base,该类基于boost asio实现了连接服务器,发送请求,获取响应和解析http数据等操作,该类的大致实现框架如下
1
class
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
27private:
28
29 void handle_connect(const boost::system::error_code& e)
30 {
31 if(!e)
32 onConnect();
33 else
34 onIoError(e);
35 }
36
37 void handle_write(const boost::system::error_code& e)
38 {
39 if(!e)
40 onWrite();
41 else
42 onIoError(e);
43 }
44
45protected:
46 virtual void onConnect(){}
47 virtual void onWrite(){}
48 virtual void onIoError(const boost::system::error_code& e){}
49
50private:
51 boost::asio::ip::tcp::socket socket_;
52 boost::asio::ip::tcp::resolver resolver_;
53 boost::asio::streambuf request_, response_;
54} ;
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
27private:
28
29 void handle_connect(const boost::system::error_code& e)
30 {
31 if(!e)
32 onConnect();
33 else
34 onIoError(e);
35 }
36
37 void handle_write(const boost::system::error_code& e)
38 {
39 if(!e)
40 onWrite();
41 else
42 onIoError(e);
43 }
44
45protected:
46 virtual void onConnect(){}
47 virtual void onWrite(){}
48 virtual void onIoError(const boost::system::error_code& e){}
49
50private:
51 boost::asio::ip::tcp::socket socket_;
52 boost::asio::ip::tcp::resolver resolver_;
53 boost::asio::streambuf request_, response_;
54} ;
框架实现
基类模板
1
template
<
typename T
>
2 class 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
13public:
14 virtual ~boost_socket_base()
15 { }
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 typename T::lowest_layer_type& lowest_layer()
46 {
47 ssl_socket_base_t* p = get_ssl_socket();
48 return p ? p->lowest_layer() : get_socket()->lowest_layer();
49 }
50
51 template <typename MutableBufferSequence>
52 std::size_t read_some(const MutableBufferSequence& buffers,boost::system::error_code& ec)
53 {
54 ssl_socket_base_t* p = get_ssl_socket();
55 return p ? p->read_some(buffers) : get_socket()->read_some(buffers,ec);
56 }
57
58 template <typename MutableBufferSequence>
59 std::size_t read_some(const MutableBufferSequence& buffers)
60 {
61 //与上面相同,但不带ec
62 }
63
64 template <typename MutableBufferSequence, typename ReadHandler>
65 void async_read_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
66 {
67 ssl_socket_base_t* p = get_ssl_socket();
68 return p ? p->async_read_some(buffers,handler) : get_socket()->async_read_some(buffers,handler);
69 }
70
71 template <typename ConstBufferSequence>
72 std::size_t write_some(const ConstBufferSequence& buffers,boost::system::error_code& ec)
73 {
74 ssl_socket_base_t* p = get_ssl_socket();
75 return p ? p->write_some(buffers,ec) : get_socket()->write_some(buffers,ec);
76 }
77
78 template <typename ConstBufferSequence>
79 std::size_t write_some(const ConstBufferSequence& buffers)
80 {
81 //与上面相同,但不带ec
82 }
83
84 template <typename MutableBufferSequence, typename ReadHandler>
85 void async_write_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
86 {
87 ssl_socket_base_t* p = get_ssl_socket();
88 return p ? p->async_write_some(buffers,handler) : get_socket()->async_write_some(buffers,handler);
89 }
90
91private:
92 boost::tribool tb_;
93 union {
94 ssl_socket_base_t* ss_;
95 socket_base_t* s_;
96 };
97} ;
2 class 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
13public:
14 virtual ~boost_socket_base()
15 { }
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 typename T::lowest_layer_type& lowest_layer()
46 {
47 ssl_socket_base_t* p = get_ssl_socket();
48 return p ? p->lowest_layer() : get_socket()->lowest_layer();
49 }
50
51 template <typename MutableBufferSequence>
52 std::size_t read_some(const MutableBufferSequence& buffers,boost::system::error_code& ec)
53 {
54 ssl_socket_base_t* p = get_ssl_socket();
55 return p ? p->read_some(buffers) : get_socket()->read_some(buffers,ec);
56 }
57
58 template <typename MutableBufferSequence>
59 std::size_t read_some(const MutableBufferSequence& buffers)
60 {
61 //与上面相同,但不带ec
62 }
63
64 template <typename MutableBufferSequence, typename ReadHandler>
65 void async_read_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
66 {
67 ssl_socket_base_t* p = get_ssl_socket();
68 return p ? p->async_read_some(buffers,handler) : get_socket()->async_read_some(buffers,handler);
69 }
70
71 template <typename ConstBufferSequence>
72 std::size_t write_some(const ConstBufferSequence& buffers,boost::system::error_code& ec)
73 {
74 ssl_socket_base_t* p = get_ssl_socket();
75 return p ? p->write_some(buffers,ec) : get_socket()->write_some(buffers,ec);
76 }
77
78 template <typename ConstBufferSequence>
79 std::size_t write_some(const ConstBufferSequence& buffers)
80 {
81 //与上面相同,但不带ec
82 }
83
84 template <typename MutableBufferSequence, typename ReadHandler>
85 void async_write_some(const MutableBufferSequence& buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
86 {
87 ssl_socket_base_t* p = get_ssl_socket();
88 return p ? p->async_write_some(buffers,handler) : get_socket()->async_write_some(buffers,handler);
89 }
90
91private:
92 boost::tribool tb_;
93 union {
94 ssl_socket_base_t* ss_;
95 socket_base_t* s_;
96 };
97} ;
子类模板
1
template
<
typename T
>
2 class boost_ssl_socket : public boost_socket_base < T >
3 , public boost::asio::ssl::stream < T >
4 {
5public:
6 typedef boost::asio::ssl::stream<T> base2;
7
8 boost_ssl_socket(boost::asio::io_service& io_service,boost::asio::ssl::context& ctx)
9 :base2(io_service,ctx)
10 { }
11} ;
12
13 template < typename T >
14 class boost_socket : public boost_socket_base < T >
15 , public T
16 {
17public:
18 typedef T base2;
19
20 boost_socket(boost::asio::io_service& io_service)
21 :base2(io_service)
22 { }
23} ;
2 class boost_ssl_socket : public boost_socket_base < T >
3 , public boost::asio::ssl::stream < T >
4 {
5public:
6 typedef boost::asio::ssl::stream<T> base2;
7
8 boost_ssl_socket(boost::asio::io_service& io_service,boost::asio::ssl::context& ctx)
9 :base2(io_service,ctx)
10 { }
11} ;
12
13 template < typename T >
14 class boost_socket : public boost_socket_base < T >
15 , public T
16 {
17public:
18 typedef T base2;
19
20 boost_socket(boost::asio::io_service& io_service)
21 :base2(io_service)
22 { }
23} ;
应用改进
使用上面ssl socket框架后,只须5个地方稍作改动即可。
1)成员变量:由原来的boost::asio::ip::tcp改为boost_socket_base<boost_tcp_socket>*类型。
1
typedef boost::asio::ip::tcp::socket boost_tcp_s
ocket;
2 boost_socket_base < boost_tcp_socket >* socket_;
2 boost_socket_base < boost_tcp_socket >* socket_;
2)构造函数 :增加boost::asio::ssl::context* ctx参数,默认为NULL,表示不使用ssl。
1
http_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}
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。
1
void
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}
13 void handle_handshake( const boost::system::error_code & e)
14 {
15 if(!e)
16 onConnect();
17 else
18 onIoError(e);
19}
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}
13 void 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。
1
void
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}
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调用:将参数socket_改为*socket_,例如下。
1
void
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}
9 void 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}
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}
9 void 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}