1. 程式人生 > >基於boost asio實現的ssl socket框架

基於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(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