• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-159  評論-223  文章-30  trackbacks-0
            情景分析
               現已存在一個可用穩定的異步客戶端類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    
             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}
            ;
               顯而易見,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        }
            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}
            ;
              考慮到dynamic_cast轉換的性能開銷,因此增加了三態邏輯變量tb_和union指針,tb_表示當前this實際指向的對象類型,初始化為indeterminate,true表示ssl socket對象,使用ss_;false表示普通socket對象,使用s_。這樣一來,當且僅當tb_為indeterminate時才dynamic_cast。由于這點優化僅對基類指針操作有效,而對派生對象實無必要,所以tb_和union指針設為私有的;而且基類指針可以指向不同的子類對象,所以增加了reset方法重設tb_為indeterminate狀態,保證行為的正確性。

               子類模板 
             1template<typename T> 
             2class 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
            13template<typename T>
            14class 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}
            ;
              boost_ssl_socket為ssl套接字類模板,boost_socket為普通套接字類模板,使用多重繼承,第1基類為boost_socket_base<T>,第2基類分別為asio:ssl:stream<T>和T。

            應用改進
               使用上面ssl socket框架后,只須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調用
            :將參數socket_改為*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}
            posted on 2013-03-20 20:47 春秋十二月 閱讀(12308) 評論(2)  編輯 收藏 引用 所屬分類: Opensrc

            評論:
            # re: 基于boost asio實現的支持ssl的通用socket框架 2013-03-21 11:47 | wem
            學習了  回復  更多評論
              
            # re: 基于boost asio實現的支持ssl的通用socket框架 2013-06-08 09:36 |
            最近才看過boost的asio ,現在能看懂點這篇博客了。  回復  更多評論
              
            久久久久精品国产亚洲AV无码| 亚洲国产另类久久久精品| 欧美亚洲国产精品久久高清| 欧美777精品久久久久网| 无码人妻精品一区二区三区久久 | 亚洲色欲久久久久综合网| 精品精品国产自在久久高清| 久久精品国产亚洲AV无码麻豆 | 99久久99久久| 久久亚洲私人国产精品vA| 久久天天躁狠狠躁夜夜不卡| 亚洲综合伊人久久综合| 久久久国产精华液| 久久青青草原亚洲av无码app | 国产精品美女久久久久av爽| 欧美久久久久久精选9999| 久久精品国产免费| 国产精品日韩欧美久久综合| 久久九九久精品国产| 欧美成a人片免费看久久| 亚洲欧美国产日韩综合久久| 久久无码专区国产精品发布| 少妇无套内谢久久久久| 久久精品国产亚洲AV高清热 | 亚洲乱码日产精品a级毛片久久| 欧美激情精品久久久久久| 亚洲人成无码www久久久| 久久精品www人人爽人人| 狠狠色丁香婷婷综合久久来来去| 亚洲人AV永久一区二区三区久久| 日韩人妻无码一区二区三区久久 | 办公室久久精品| 最新久久免费视频| 国产精品一久久香蕉国产线看观看| 狠狠色丁香婷婷综合久久来来去 | 日韩中文久久| 亚洲国产精品一区二区久久hs| 久久99精品久久久久久噜噜| 18岁日韩内射颜射午夜久久成人 | 狠狠色丁香婷婷综合久久来来去 | 91精品国产91久久|