一家专做土特产的网站,做网站品,成都建设网站分享,网站建设案例分享情景分析现已存在一个可用稳定的异步客户端类http_client_base#xff0c;该类基于boost asio实现了连接服务器#xff0c;发送请求#xff0c;获取响应和解析http数据等操作#xff0c;该类的大致实现框架如下1classhttp_client_base 2{ 3public: 4 http_client_ba…情景分析现已存在一个可用稳定的异步客户端类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_placefalse) 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 27 void async_write_some(const void* data,size_t size,bool in_placefalse) 28 { 29 if(!in_place){ 30 //do something 31 boost::asio::async_write(socket_,request_, 32 boost::bind(http_client::handle_write_some,this,boost::asio::placeholders::error)); 33 }else 34 boost::asio::async_write(socket_,boost::asio::buffer(data,size), 35 boost::bind(http_client::handle_write_some,this,boost::asio::placeholders::error)); 36 } 37 38private: 39 void handle_resolve(const boost::system::error_code e,boost::asio::ip::tcp::resolver::iterator endpoint_iterator) 40 { 41 if (!e) 42 boost::asio::async_connect(socket_, endpoint_iterator, 43 boost::bind(http_client::handle_connect,this,boost::asio::placeholders::error)); 44 else 45 onIoError(e); 46 } 47 48 void handle_connect(const boost::system::error_code e) 49 { 50 if(!e) 51 onConnect(); 52 else 53 onIoError(e); 54 } 55 56 void handle_write_some(const boost::system::error_code e) 57 { 58 if(!e) 59 onWriteSome(); 60 else 61 onIoError(e); 62 } 63 64 void handle_write(const boost::system::error_code e) 65 { 66 if(!e) 67 boost::asio::async_read_until(socket_, response_,\r\n\r\n, 68 boost::bind(http_client::handle_read_header,this, 69 boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); 70 else 71 onIoError(e); 72 } 73 74 void handle_read_header(const boost::system::error_code e,size_t bytes_transferred) 75 { 76 if(!e){ 77 //do something 78 boost::asio::async_read(socket_,response_,asio::transfer_at_least(1), 79 boost::bind(http_client::handle_read_content,this, 80 boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred); 81 }else 82 onIoError(e); 83 } 84 85 void handle_read_content(const boost::system::error_code e,size_t bytes_transferred) 86 { 87 if(!e){ 88 //do something 89 boost::asio::async_read(socket_,response_,asio::transfer_at_least(1), 90 boost::bind(http_client::handle_read_content,this, 91 boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred)); 92 }else 93 onIoError(e); 94 } 95 96protected: 97 virtual void onConnect(){} 98 virtual void onWriteSome(){} 99 virtual void onIoError(const boost::system::error_code e){} 100 101private: 102 boost::asio::ip::tcp::socket socket_; 103 boost::asio::ip::tcp::resolver resolver_; 104 boost::asio::streambuf request_; 105 boost::asio::streambuf response_; 106}; 显而易见http_client_base使用tcp::socket作为底层实现所以数据是非ssl传输的。现因需求变更为了数据安全要求使用ssl传输。但boost asio中的ssl::stream类接口和tcp::socket有所不同。其实在非ssl和ssl间不同的只是读写数据的方法而数据处理逻辑不变因此为了重用http_client_base的机制框架和对http数据的解析那么怎么使http_client_base不作大的改动就支持ssl呢通过研究boost asio源码发现async_xxx系列自由函数内部要求读写流实现read_some、async_read_some、write_some和async_write_some4个短读写方法。由于tcp::socket已实现短读写而且ssl::stream是tcp::socket的上层因此只要设计一个抽象的基类流使之支持read_some、async_some_read、w
rite
_some和async_write_some即可而实现使用dynamic_cast转到兄弟基类tcp::socket或ssl::stream再调用它们对应的同名短读写方法另外还需要给出获取最底层socket的接口以支持async_connect和connect方法。因此针对这一设计实现则要求派生类必须同时从抽象基类和其兄弟基类tcp::socket或ssl::stream继承。框架实现1templatetypename T 2class boost_socket_base 3{ 4public: 5 typedef boost::asio::ssl::streamT ssl_socket_base_t; 6 typedef T socket_base_t; 7 8protected: 9 boost_socket_base() 10 :tb_(boost::indeterminate) 11 { 12 } 13 14public: 15 virtual ~boost_socket_base() {} 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_castssl_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_castsocket_base_t*(this)) 40 tb_ false; 41 return s_; 42 } 43 } 44 45 void reset() 46 { tb_ boost::indeterminate; } 47 48 typename T::lowest_layer_type lowest_layer() 49 { 50 ssl_socket_base_t* p get_ssl_socket(); 51 if(p) 52 return p-lowest_layer(); 53 else 54 return get_socket()-lowest_layer(); 55 } 56 57 template typename MutableBufferSequence 58 std::size_t read_some(const MutableBufferSequence buffers) 59 { 60 ssl_socket_base_t* p get_ssl_socket(); 61 if(p) 62 return p-read_some(buffers); 63 else 64 return get_socket()-read_some(buffers); 65 } 66 67 template typename MutableBufferSequence 68 std::size_t read_some(const MutableBufferSequence buffers,boost::system::error_code ec) 69 { 70 ssl_socket_base_t* p get_ssl_socket(); 71 if(p) 72 return p-read_some(buffers,ec); 73 else 74 return get_socket()-read_some(buffers,ec); 75 } 76 77 template typename MutableBufferSequence, typename ReadHandler 78 void async_read_some(const MutableBufferSequence buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler) 79 { 80 ssl_socket_base_t* p get_ssl_socket(); 81 if(p) 82 return p-async_read_some(buffers,handler); 83 else 84 return get_socket()-async_read_some(buffers,handler); 85 } 86 87 template typename ConstBufferSequence 88 std::size_t write_some(const ConstBufferSequence buffers,boost::system::error_code ec) 89 { 90 ssl_socket_base_t* p get_ssl_socket(); 91 if(p) 92 return p-write_some(buffers,ec); 93 else 94 return get_socket()-write_some(buffers,ec); 95 } 96 97 template typename ConstBufferSequence 98 std::size_t write_some(const ConstBufferSequence buffers) 99 { 100 ssl_socket_base_t* p get_ssl_socket(); 101 if(p) 102 return p-write_some(buffers); 103 else 104 return get_socket()-write_some(buffers); 105 } 106 107 template typename MutableBufferSequence, typename ReadHandler 108 void async_write_some(const MutableBufferSequence buffers,BOOST_ASIO_MOVE_ARG(ReadHandler) handler) 109 { 110 ssl_socket_base_t* p get_ssl_socket(); 111 if(p) 112 return p-async_write_some(buffers,handler); 113 else 114 return get_socket()-async_write_some(buffers,handler); 115 } 116 117private: 118 boost::tribool tb_; 119 union { 120 ssl_socket_base_t* ss_; 121 socket_base_t* s_; 122 }; 123}; 考虑到dynamic_cast转换的性能开销因此增加了三态逻辑变量tb_和union指针tb_表示当前this实际指向的对象类型初始化为indeterminatetrue表示ssl socket对象使用ss_false表示普通socket对象使用s_。这样一来当且仅当tb_为indeterminate时才dynamic_cast。由于这点优化仅对基类指针操作有效而对派生对象实无必要所以tb_和union指针设为私有的而且基类指针可以指向不同的子类对象所以增加了reset方法重设tb_为indeterminate状态保证行为的正确性。应用改进使用boost_socket_base框架后只须5个地方稍作改动即可。1成员变量
由原来的boost::asio::ip::tcp改为boost_socket_baseboost_tcp_socket*类型。1typedef boost::asio::ip::tcp::socket boost_tcp_socket; 2boost_socket_baseboost_tcp_socket* socket_; 2构造函数
增加boost::asio::ssl::context* ctx参数默认为NULL表示不使用ssl。1http_client_base(boost::asio::io_service io_service,boost::asio::ssl::context* ctxNULL) 2 :resolver_(io_service) 3{ 4 if(ctx) 5 socket_ new boost_ssl_socketboost_tcp_socket(io_service,*ctx); 6 else 7 socket_ new boost_socketboost_tcp_socket(io_service); 8} 3握手
处理
与非ssl不同的是在连接后需要进行握手握手成功后才回调onConnect。1void handle_connect(const boost::system::error_code e) 2{ 3 if(!e){ 4 boost_socket_baseboost_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} 5async_xxx调用
将参数socet_改为*socket_例如下。1void async_write(const void* data,size_t size,bool in_placefalse) 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}