• <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  評(píng)論-223  文章-30  trackbacks-0
            情景分析
               現(xiàn)已存在一個(gè)可用穩(wěn)定的異步客戶端類http_client_base,該類基于boost asio實(shí)現(xiàn)了連接服務(wù)器,發(fā)送請(qǐng)求,獲取響應(yīng)和解析http數(shù)據(jù)等操作,該類的大致實(shí)現(xiàn)框架如下
              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}
            ;
               顯而易見(jiàn),http_client_base使用tcp::socket作為底層實(shí)現(xiàn),所以數(shù)據(jù)是非ssl傳輸?shù)摹,F(xiàn)因需求變更,為了數(shù)據(jù)安全要求使用ssl傳輸。但boost asio中的ssl::stream類接口和tcp::socket有所不同。其實(shí)在非ssl和ssl間,不同的只是讀寫(xiě)數(shù)據(jù)的方法,而數(shù)據(jù)處理邏輯不變,因此為了重用http_client_base的機(jī)制框架和對(duì)http數(shù)據(jù)的解析,那么怎么使http_client_base不作大的改動(dòng)就支持ssl呢?通過(guò)研究asio源碼發(fā)現(xiàn),async_xxx系列自由函數(shù)內(nèi)部要求讀寫(xiě)流實(shí)現(xiàn)read_some、async_read_some、write_some和async_write_some4個(gè)短讀寫(xiě)方法。由于tcp::socket已實(shí)現(xiàn)短讀寫(xiě)而且ssl::stream是tcp::socket的上層,因此只要設(shè)計(jì)一個(gè)抽象的基類流,使之支持read_some、async_some_read、write_some和async_write_some即可,而實(shí)現(xiàn)使用dynamic_cast轉(zhuǎn)到兄弟基類tcp::socket或ssl::stream,再調(diào)用它們對(duì)應(yīng)的同名短讀寫(xiě)方法;另外還需要給出獲取最底層socket的接口,以支持async_connect和connect方法。因此針對(duì)這一設(shè)計(jì)實(shí)現(xiàn),則要求派生類必須同時(shí)從抽象基類和其兄弟基類tcp::socket或ssl::stream繼承。

            框架實(shí)現(xiàn)
               基類模板  
             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轉(zhuǎn)換的性能開(kāi)銷,因此增加了三態(tài)邏輯變量tb_和union指針,tb_表示當(dāng)前this實(shí)際指向的對(duì)象類型,初始化為indeterminate,true表示ssl socket對(duì)象,使用ss_;false表示普通socket對(duì)象,使用s_。這樣一來(lái),當(dāng)且僅當(dāng)tb_為indeterminate時(shí)才dynamic_cast。由于這點(diǎn)優(yōu)化僅對(duì)基類指針操作有效,而對(duì)派生對(duì)象實(shí)無(wú)必要,所以tb_和union指針設(shè)為私有的;而且基類指針可以指向不同的子類對(duì)象,所以增加了reset方法重設(shè)tb_為indeterminate狀態(tài),保證行為的正確性。

               子類模板 
             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。

            應(yīng)用改進(jìn)
               使用上面ssl socket框架后,只須5個(gè)地方稍作改動(dòng)即可。
               1)成員變量:由原來(lái)的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)構(gòu)造函數(shù):增加boost::asio::ssl::context* ctx參數(shù),默認(rèn)為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不同的是,在連接后需要進(jìn)行握手,握手成功后才回調(diào)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作為參數(shù),因此需要調(diào)用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調(diào)用
            :將參數(shù)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 春秋十二月 閱讀(12310) 評(píng)論(2)  編輯 收藏 引用 所屬分類: Opensrc

            評(píng)論:
            # re: 基于boost asio實(shí)現(xiàn)的支持ssl的通用socket框架 2013-03-21 11:47 | wem
            學(xué)習(xí)了  回復(fù)  更多評(píng)論
              
            # re: 基于boost asio實(shí)現(xiàn)的支持ssl的通用socket框架 2013-06-08 09:36 |
            最近才看過(guò)boost的asio ,現(xiàn)在能看懂點(diǎn)這篇博客了。  回復(fù)  更多評(píng)論
              
            Xx性欧美肥妇精品久久久久久| 九九精品99久久久香蕉| 久久国产精品二国产精品| 久久精品亚洲欧美日韩久久| 久久亚洲国产成人影院| 久久人与动人物a级毛片| 久久久精品国产sm调教网站| 7国产欧美日韩综合天堂中文久久久久 | 欧美国产精品久久高清| 久久精品一本到99热免费| …久久精品99久久香蕉国产| 久久国产精品一区| 少妇久久久久久久久久| 国产—久久香蕉国产线看观看| 久久99九九国产免费看小说| 72种姿势欧美久久久久大黄蕉 | 久久夜色精品国产欧美乱| 伊人久久综合热线大杳蕉下载| 亚洲欧美成人久久综合中文网| 97热久久免费频精品99| 亚洲精品乱码久久久久久蜜桃| 99久久中文字幕| 久久精品中文字幕一区 | 久久久久亚洲精品日久生情| 国内精品久久久久| 久久精品国产亚洲AV不卡| 精品国产乱码久久久久久浪潮 | 亚洲国产成人久久综合一区77| 久久99国产亚洲高清观看首页| 中文成人无码精品久久久不卡 | 精品国产乱码久久久久久1区2区| 国产亚洲成人久久| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 久久天天躁夜夜躁狠狠| 久久久久久av无码免费看大片| 久久久无码人妻精品无码| 区久久AAA片69亚洲| 久久久久久久久久免免费精品| 国产Av激情久久无码天堂| 亚洲精品白浆高清久久久久久| 香蕉久久永久视频|