基於boost asio實現的ssl socket框架
阿新 • • 發佈:2018-12-22
情景分析
現已存在一個可用穩定的非同步客戶端類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(constvoid* 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 virtualvoid onConnect(){} 47 virtualvoid onWrite(){} 48 virtualvoid 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}; 顯而易見,http_client_base使用tcp::socket作為底層實現,所以資料是非ssl傳輸的。現因需求變更,為了資料安全要求使用ssl傳輸。但boost asio中的ssl::stream類介面和tcp::socket有所不同。其實在非ssl和ssl間,不同的只是讀寫資料的方法,而資料處理邏輯不變,因此為了重用http_client_base的機制框架和對http資料的解析,那麼怎麼使http_client_base不作大的改動就支援ssl呢?通過研究asio原始碼發現,async_xxx系列自由函式內部要求讀寫流實現read_some、async_read_some、write_some和async_write_some4個短讀寫方法。由於tcp::socket已實現短讀寫而且ssl::stream是tcp::socket的上層,因此只要設計一個抽象的基類流,使之支援read_some、async_some_read、write_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
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 }elseif(!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 }elseif(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 //與上面相同,但不帶ec62 }63
64 template <typename MutableBufferSequence, typename ReadHandler>65 void async_read_some(c
現已存在一個可用穩定的非同步客戶端類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(
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));
16 void async_write(constvoid* 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));
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 virtualvoid onConnect(){} 47 virtualvoid onWrite(){} 48 virtualvoid 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}; 顯而易見,http_client_base使用tcp::socket作為底層實現,所以資料是非ssl傳輸的。現因需求變更,為了資料安全要求使用ssl傳輸。但boost asio中的ssl::stream類介面和tcp::socket有所不同。其實在非ssl和ssl間,不同的只是讀寫資料的方法,而資料處理邏輯不變,因此為了重用http_client_base的機制框架和對http資料的解析,那麼怎麼使http_client_base不作大的改動就支援ssl呢?通過研究asio原始碼發現,async_xxx系列自由函式內部要求讀寫流實現read_some、async_read_some、write_some和async_write_some4個短讀寫方法。由於tcp::socket已實現短讀寫而且ssl::stream是tcp::socket的上層,因此只要設計一個抽象的基類流,使之支援read_some、async_some_read、write_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
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 }elseif(!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 }elseif(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 //與上面相同,但不帶ec62 }63
64 template <typename MutableBufferSequence, typename ReadHandler>65 void async_read_some(c