boost asio 学习(九) boost::asio 网络封装
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-
started-with-boostasio?pg=10
9. A boost::asio network wrapper (TCP)
现在我们了解asio和TCP网络方面的知识,我们可以尝试下封装网络底层。通过使用这个封装,我们可以重用代码并且将精力集中于业务逻
辑方面而不在网络通讯方面花费太多精力。
重要提示:本代码仅仅用于教学目的。不要在商业系统中使用该代码,因为它可能存在BUG.代码是设计用来在特定环境运行,因此在非预
计环境中可能会出现异常情况。本人在几个项目中使用该代码,遇到过几个需要修改的小问题。
另外,代码中使用了vector和list以及shared_ptr,可能造成大量的分配操作,在某些环境下是不适用的。代码仅仅是用以教学目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | #pragma once #ifndef NETWORK_H_ #define NETWORK_H_ //----------------------------------------------------------------------------- #include <boost/asio.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/shared_ptr.hpp> #include <string> #include <vector> #include <list> #include <boost/cstdint.hpp> //----------------------------------------------------------------------------- using boost::uint64_t; using boost::uint32_t; using boost::uint16_t; using boost::uint8_t; using boost::int64_t; using boost::int32_t; using boost::int16_t; using boost::int8_t; //----------------------------------------------------------------------------- class Hive; class Acceptor; class Connection; //----------------------------------------------------------------------------- class Connection : public boost::enable_shared_from_this< Connection > { friend class Acceptor; friend class Hive; private : boost::shared_ptr< Hive > m_hive; boost::asio::ip::tcp::socket m_socket; boost::asio::strand m_io_strand; boost::asio::deadline_timer m_timer; boost::posix_time::ptime m_last_time; std::vector< uint8_t > m_recv_buffer; std::list< int32_t > m_pending_recvs; std::list< std::vector< uint8_t > > m_pending_sends; int32_t m_receive_buffer_size; int32_t m_timer_interval; volatile uint32_t m_error_state; protected : Connection( boost::shared_ptr< Hive > hive ); virtual ~Connection(); private : Connection( const Connection & rhs ); Connection & operator =( const Connection & rhs ); void StartSend(); void StartRecv( int32_t total_bytes ); void StartTimer(); void StartError( const boost::system::error_code & error ); void DispatchSend( std::vector< uint8_t > buffer ); void DispatchRecv( int32_t total_bytes ); void DispatchTimer( const boost::system::error_code & error ); void HandleConnect( const boost::system::error_code & error ); void HandleSend( const boost::system::error_code & error, std::list< std::vector< uint8_t > >::iterator itr ); void HandleRecv( const boost::system::error_code & error, int32_t actual_bytes ); void HandleTimer( const boost::system::error_code & error ); private : // Called when the connection has successfully connected to the local // host. virtual void OnAccept( const std:: string & host, uint16_t port ) = 0; // Called when the connection has successfully connected to the remote // host. virtual void OnConnect( const std:: string & host, uint16_t port ) = 0; // Called when data has been sent by the connection. virtual void OnSend( const std::vector< uint8_t > & buffer ) = 0; // Called when data has been received by the connection. virtual void OnRecv( std::vector< uint8_t > & buffer ) = 0; // Called on each timer event. virtual void OnTimer( const boost::posix_time::time_duration & delta ) = 0; // Called when an error is encountered. virtual void OnError( const boost::system::error_code & error ) = 0; public : // Returns the Hive object. boost::shared_ptr< Hive > GetHive(); // Returns the socket object. boost::asio::ip::tcp::socket & GetSocket(); // Returns the strand object. boost::asio::strand & GetStrand(); // Sets the application specific receive buffer size used. For stream // based protocols such as HTTP, you want this to be pretty large, like // 64kb. For packet based protocols, then it will be much smaller, // usually 512b - 8kb depending on the protocol. The default value is // 4kb. void SetReceiveBufferSize( int32_t size ); // Returns the size of the receive buffer size of the current object. int32_t GetReceiveBufferSize() const ; // Sets the timer interval of the object. The interval is changed after // the next update is called. void SetTimerInterval( int32_t timer_interval_ms ); // Returns the timer interval of the object. int32_t GetTimerInterval() const ; // Returns true if this object has an error associated with it. bool HasError(); // Binds the socket to the specified interface. void Bind( const std:: string & ip, uint16_t port ); // Starts an a/synchronous connect. void Connect( const std:: string & host, uint16_t port ); // Posts data to be sent to the connection. void Send( const std::vector< uint8_t > & buffer ); // Posts a recv for the connection to process. If total_bytes is 0, then // as many bytes as possible up to GetReceiveBufferSize() will be // waited for. If Recv is not 0, then the connection will wait for exactly // total_bytes before invoking OnRecv. void Recv( int32_t total_bytes = 0 ); // Posts an asynchronous disconnect event for the object to process. void Disconnect(); }; //----------------------------------------------------------------------------- class Acceptor : public boost::enable_shared_from_this< Acceptor > { friend class Hive; private : boost::shared_ptr< Hive > m_hive; boost::asio::ip::tcp::acceptor m_acceptor; boost::asio::strand m_io_strand; boost::asio::deadline_timer m_timer; boost::posix_time::ptime m_last_time; int32_t m_timer_interval; volatile uint32_t m_error_state; private : Acceptor( const Acceptor & rhs ); Acceptor & operator =( const Acceptor & rhs ); void StartTimer(); void StartError( const boost::system::error_code & error ); void DispatchAccept( boost::shared_ptr< Connection > connection ); void HandleTimer( const boost::system::error_code & error ); void HandleAccept( const boost::system::error_code & error, boost::shared_ptr< Connection > connection ); protected : Acceptor( boost::shared_ptr< Hive > hive ); virtual ~Acceptor(); private : // Called when a connection has connected to the server. This function // should return true to invoke the connection's OnAccept function if the // connection will be kept. If the connection will not be kept, the // connection's Disconnect function should be called and the function // should return false. virtual bool OnAccept( boost::shared_ptr< Connection > connection, const std:: string & host, uint16_t port ) = 0; // Called on each timer event. virtual void OnTimer( const boost::posix_time::time_duration & delta ) = 0; // Called when an error is encountered. Most typically, this is when the // acceptor is being closed via the Stop function or if the Listen is // called on an address that is not available. virtual void OnError( const boost::system::error_code & error ) = 0; public : // Returns the Hive object. boost::shared_ptr< Hive > GetHive(); // Returns the acceptor object. boost::asio::ip::tcp::acceptor & GetAcceptor(); // Returns the strand object. boost::asio::strand & GetStrand(); // Sets the timer interval of the object. The interval is changed after // the next update is called. The default value is 1000 ms. void SetTimerInterval( int32_t timer_interval_ms ); // Returns the timer interval of the object. int32_t GetTimerInterval() const ; // Returns true if this object has an error associated with it. bool HasError(); public : // Begin listening on the specific network interface. void Listen( const std:: string & host, const uint16_t & port ); // Posts the connection to the listening interface. The next client that // connections will be given this connection. If multiple calls to Accept // are called at a time, then they are accepted in a FIFO order. void Accept( boost::shared_ptr< Connection > connection ); // Stop the Acceptor from listening. void Stop(); }; //----------------------------------------------------------------------------- class Hive : public boost::enable_shared_from_this< Hive > { private : boost::asio::io_service m_io_service; boost::shared_ptr< boost::asio::io_service::work > m_work_ptr; volatile uint32_t m_shutdown; private : Hive( const Hive & rhs ); Hive & operator =( const Hive & rhs ); public : Hive(); virtual ~Hive(); // Returns the io_service of this object. boost::asio::io_service & GetService(); // Returns true if the Stop function has been called. bool HasStopped(); // Polls the networking subsystem once from the current thread and // returns. void Poll(); // Runs the networking system on the current thread. This function blocks // until the networking system is stopped, so do not call on a single // threaded application with no other means of being able to call Stop // unless you code in such logic. void Run(); // Stops the networking system. All work is finished and no more // networking interactions will be possible afterwards until Reset is called. void Stop(); // Restarts the networking system after Stop as been called. A new work // object is created ad the shutdown flag is cleared. void Reset(); }; //----------------------------------------------------------------------------- #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | #include "network.h" #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <boost/interprocess/detail/atomic.hpp> //----------------------------------------------------------------------------- Hive::Hive() : m_work_ptr( new boost::asio::io_service::work( m_io_service ) ), m_shutdown( 0 ) { } Hive::~Hive() { } boost::asio::io_service & Hive::GetService() { return m_io_service; } bool Hive::HasStopped() { return ( boost::interprocess::detail::atomic_cas32( &m_shutdown, 1, 1 ) == 1 ); } void Hive::Poll() { m_io_service.poll(); } void Hive::Run() { m_io_service.run(); } void Hive::Stop() { if ( boost::interprocess::detail::atomic_cas32( &m_shutdown, 1, 0 ) == 0 ) { m_work_ptr.reset(); m_io_service.run(); m_io_service.stop(); } } void Hive::Reset() { if ( boost::interprocess::detail::atomic_cas32( &m_shutdown, 0, 1 ) == 1 ) { m_io_service.reset(); m_work_ptr.reset( new boost::asio::io_service::work( m_io_service ) ); } } //----------------------------------------------------------------------------- Acceptor::Acceptor( boost::shared_ptr< Hive > hive ) : m_hive( hive ), m_acceptor( hive->GetService() ), m_io_strand( hive->GetService() ), m_timer( hive->GetService() ), m_timer_interval( 1000 ), m_error_state( 0 ) { } Acceptor::~Acceptor() { } void Acceptor::StartTimer() { m_last_time = boost::posix_time::microsec_clock::local_time(); m_timer.expires_from_now( boost::posix_time::milliseconds( m_timer_interval ) ); m_timer.async_wait( m_io_strand.wrap( boost::bind( &Acceptor::HandleTimer, shared_from_this(), _1 ) ) ); } void Acceptor::StartError( const boost::system::error_code & error ) { if ( boost::interprocess::detail::atomic_cas32( &m_error_state, 1, 0 ) == 0 ) { boost::system::error_code ec; m_acceptor.cancel( ec ); m_acceptor.close( ec ); m_timer.cancel( ec ); OnError( error ); } } void Acceptor::DispatchAccept( boost::shared_ptr< Connection > connection ) { m_acceptor.async_accept( connection->GetSocket(), connection->GetStrand().wrap( boost::bind( &Acceptor::HandleAccept, shared_from_this(), _1, connection ) ) ); } void Acceptor::HandleTimer( const boost::system::error_code & error ) { if ( error || HasError() || m_hive->HasStopped() ) { StartError( error ); } else { OnTimer( boost::posix_time::microsec_clock::local_time() - m_last_time ); StartTimer(); } } void Acceptor::HandleAccept( const boost::system::error_code & error, boost::shared_ptr< Connection > connection ) { if ( error || HasError() || m_hive->HasStopped() ) { connection->StartError( error ); } else { if ( connection->GetSocket().is_open() ) { connection->StartTimer(); if ( OnAccept( connection, connection->GetSocket().remote_endpoint().address().to_string(), connection->GetSocket().remote_endpoint().port() ) ) { connection->OnAccept( m_acceptor.local_endpoint().address().to_string(), m_acceptor.local_endpoint().port() ); } } else { StartError( error ); } } } void Acceptor::Stop() { m_io_strand.post( boost::bind( &Acceptor::HandleTimer, shared_from_this(), boost::asio::error::connection_reset ) ); } void Acceptor::Accept( boost::shared_ptr< Connection > connection ) { m_io_strand.post( boost::bind( &Acceptor::DispatchAccept, shared_from_this(), connection ) ); } void Acceptor::Listen( const std:: string & host, const uint16_t & port ) { boost::asio::ip::tcp::resolver resolver( m_hive->GetService() ); boost::asio::ip::tcp::resolver::query query( host, boost::lexical_cast< std:: string >( port ) ); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve( query ); m_acceptor.open( endpoint.protocol() ); m_acceptor.set_option( boost::asio::ip::tcp::acceptor::reuse_address( false ) ); m_acceptor.bind( endpoint ); m_acceptor.listen( boost::asio::socket_base::max_connections ); StartTimer(); } boost::shared_ptr< Hive > Acceptor::GetHive() { return m_hive; } boost::asio::ip::tcp::acceptor & Acceptor::GetAcceptor() { return m_acceptor; } int32_t Acceptor::GetTimerInterval() const { return m_timer_interval; } void Acceptor::SetTimerInterval( int32_t timer_interval ) { m_timer_interval = timer_interval; } bool Acceptor::HasError() { return ( boost::interprocess::detail::atomic_cas32( &m_error_state, 1, 1 ) == 1 ); } //----------------------------------------------------------------------------- Connection::Connection( boost::shared_ptr< Hive > hive ) : m_hive( hive ), m_socket( hive->GetService() ), m_io_strand( hive->GetService() ), m_timer( hive->GetService() ), m_receive_buffer_size( 4096 ), m_timer_interval( 1000 ), m_error_state( 0 ) { } Connection::~Connection() { } void Connection::Bind( const std:: string & ip, uint16_t port ) { boost::asio::ip::tcp::endpoint endpoint( boost::asio::ip::address::from_string( ip ), port ); m_socket.open( endpoint.protocol() ); m_socket.set_option( boost::asio::ip::tcp::acceptor::reuse_address( false ) ); m_socket.bind( endpoint ); } void Connection::StartSend() { if ( !m_pending_sends.empty() ) { boost::asio::async_write( m_socket, boost::asio::buffer( m_pending_sends.front() ), m_io_strand.wrap( boost::bind( &Connection::HandleSend, shared_from_this(), boost::asio::placeholders::error, m_pending_sends.begin() ) ) ); } } void Connection::StartRecv( int32_t total_bytes ) { if ( total_bytes > 0 ) { m_recv_buffer.resize( total_bytes ); boost::asio::async_read( m_socket, boost::asio::buffer( m_recv_buffer ), m_io_strand.wrap( boost::bind( &Connection::HandleRecv, shared_from_this(), _1, _2 ) ) ); } else { m_recv_buffer.resize( m_receive_buffer_size ); m_socket.async_read_some( boost::asio::buffer( m_recv_buffer ), m_io_strand.wrap( boost::bind( &Connection::HandleRecv, shared_from_this(), _1, _2 ) ) ); } } void Connection::StartTimer() { m_last_time = boost::posix_time::microsec_clock::local_time(); m_timer.expires_from_now( boost::posix_time::milliseconds( m_timer_interval ) ); m_timer.async_wait( m_io_strand.wrap( boost::bind( &Connection::DispatchTimer, shared_from_this(), _1 ) ) ); } void Connection::StartError( const boost::system::error_code & error ) { if ( boost::interprocess::detail::atomic_cas32( &m_error_state, 1, 0 ) == 0 ) { boost::system::error_code ec; m_socket.shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec ); m_socket.close( ec ); m_timer.cancel( ec ); OnError( error ); } } void Connection::HandleConnect( const boost::system::error_code & error ) { if ( error || HasError() || m_hive->HasStopped() ) { StartError( error ); } else { if ( m_socket.is_open() ) { OnConnect( m_socket.remote_endpoint().address().to_string(), m_socket.remote_endpoint().port() ); } else { StartError( error ); } } } void Connection::HandleSend( const boost::system::error_code & error, std::list< std::vector< uint8_t > >::iterator itr ) { if ( error || HasError() || m_hive->HasStopped() ) { StartError( error ); } else { OnSend( *itr ); m_pending_sends.erase( itr ); StartSend(); } } void Connection::HandleRecv( const boost::system::error_code & error, int32_t actual_bytes ) { if ( error || HasError() || m_hive->HasStopped() ) { StartError( error ); } else { m_recv_buffer.resize( actual_bytes ); OnRecv( m_recv_buffer ); m_pending_recvs.pop_front(); if ( !m_pending_recvs.empty() ) { StartRecv( m_pending_recvs.front() ); } } } void Connection::HandleTimer( const boost::system::error_code & error ) { if ( error || HasError() || m_hive->HasStopped() ) { StartError( error ); } else { OnTimer( boost::posix_time::microsec_clock::local_time() - m_last_time ); StartTimer(); } } void Connection::DispatchSend( std::vector< uint8_t > buffer ) { bool should_start_send = m_pending_sends.empty(); m_pending_sends.push_back( buffer ); if ( should_start_send ) { StartSend(); } } void Connection::DispatchRecv( int32_t total_bytes ) { bool should_start_receive = m_pending_recvs.empty(); m_pending_recvs.push_back( total_bytes ); if ( should_start_receive ) { StartRecv( total_bytes ); } } void Connection::DispatchTimer( const boost::system::error_code & error ) { m_io_strand.post( boost::bind( &Connection::HandleTimer, shared_from_this(), error ) ); } void Connection::Connect( const std:: string & host, uint16_t port) { boost::system::error_code ec; boost::asio::ip::tcp::resolver resolver( m_hive->GetService() ); boost::asio::ip::tcp::resolver::query query( host, boost::lexical_cast< std:: string >( port ) ); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ); m_socket.async_connect( *iterator, m_io_strand.wrap( boost::bind( &Connection::HandleConnect, shared_from_this(), _1 ) ) ); StartTimer(); } void Connection::Disconnect() { m_io_strand.post( boost::bind( &Connection::HandleTimer, shared_from_this(), boost::asio::error::connection_reset ) ); } void Connection::Recv( int32_t total_bytes ) { m_io_strand.post( boost::bind( &Connection::DispatchRecv, shared_from_this(), total_bytes ) ); } void Connection::Send( const std::vector< uint8_t > & buffer ) { m_io_strand.post( boost::bind( &Connection::DispatchSend, shared_from_this(), buffer ) ); } boost::asio::ip::tcp::socket & Connection::GetSocket() { return m_socket; } boost::asio::strand & Connection::GetStrand() { return m_io_strand; } boost::shared_ptr< Hive > Connection::GetHive() { return m_hive; } void Connection::SetReceiveBufferSize( int32_t size ) { m_receive_buffer_size = size; } int32_t Connection::GetReceiveBufferSize() const { return m_receive_buffer_size; } int32_t Connection::GetTimerInterval() const { return m_timer_interval; } void Connection::SetTimerInterval( int32_t timer_interval ) { m_timer_interval = timer_interval; } bool Connection::HasError() { return ( boost::interprocess::detail::atomic_cas32( &m_error_state, 1, 1 ) == 1 ); } //----------------------------------------------------------------------------- |
网络库尝试为可简便实现的客户服务端提供一个线程安全可扩展的封装。用户能够从基本连接继承定制类,连接器等。下面这个例子展示
了如何使用封装。
第一个例子我们将学习如何使用封装设置类。例子与上面的例子很类似,简单的回应所有连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #include "network.h" #include <conio.h> #include <boost/thread/mutex.hpp> boost::mutex global_stream_lock; class MyConnection : public Connection { private : private : void OnAccept( const std:: string & host, uint16_t port ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << host << ":" << port << std::endl; global_stream_lock.unlock(); Recv(); } void OnConnect( const std:: string & host, uint16_t port ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << host << ":" << port << std::endl; global_stream_lock.unlock(); Recv(); } void OnSend( const std::vector< uint8_t > & buffer ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << buffer.size() << " bytes" << std::endl; for ( size_t x = 0; x < buffer.size(); ++x ) { std::cout << std::hex << std::setfill( '0' ) << std::setw( 2 ) << ( int )buffer[ x ] << " " ; if ( ( x + 1 ) % 16 == 0 ) { std::cout << std::endl; } } std::cout << std::endl; global_stream_lock.unlock(); } void OnRecv( std::vector< uint8_t > & buffer ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << buffer.size() << " bytes" << std::endl; for ( size_t x = 0; x < buffer.size(); ++x ) { std::cout << std::hex << std::setfill( '0' ) << std::setw( 2 ) << ( int )buffer[ x ] << " " ; if ( ( x + 1 ) % 16 == 0 ) { std::cout << std::endl; } } std::cout << std::endl; global_stream_lock.unlock(); // Start the next receive Recv(); // Echo the data back Send( buffer ); } void OnTimer( const boost::posix_time::time_duration & delta ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << delta << std::endl; global_stream_lock.unlock(); } void OnError( const boost::system::error_code & error ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << error << std::endl; global_stream_lock.unlock(); } public : MyConnection( boost::shared_ptr< Hive > hive ) : Connection( hive ) { } ~MyConnection() { } }; class MyAcceptor : public Acceptor { private : private : bool OnAccept( boost::shared_ptr< Connection > connection, const std:: string & host, uint16_t port ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << host << ":" << port << std::endl; global_stream_lock.unlock(); return true ; } void OnTimer( const boost::posix_time::time_duration & delta ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << delta << std::endl; global_stream_lock.unlock(); } void OnError( const boost::system::error_code & error ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << error << std::endl; global_stream_lock.unlock(); } public : MyAcceptor( boost::shared_ptr< Hive > hive ) : Acceptor( hive ) { } ~MyAcceptor() { } }; int main( int argc, char * argv[] ) { boost::shared_ptr< Hive > hive( new Hive() ); boost::shared_ptr< MyAcceptor > acceptor( new MyAcceptor( hive ) ); acceptor->Listen( "127.0.0.1" , 7777 ); boost::shared_ptr< MyConnection > connection( new MyConnection( hive ) ); acceptor->Accept( connection ); while ( !_kbhit() ) { hive->Poll(); Sleep( 1 ); } hive->Stop(); return 0; } |
由于使用了封装,代码很直观。所有socket管理细节都被隐藏,我们只需要注意框架逻辑。这个例子中,我们不在使用worker线程,但是
提供了同样的功能。服务器运行正常,现在来查看客户端。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | #include "network.h" #include <conio.h> #include <boost/thread/mutex.hpp> boost::mutex global_stream_lock; class MyConnection : public Connection { private : private : void OnAccept( const std:: string & host, uint16_t port ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << host << ":" << port << std::endl; global_stream_lock.unlock(); // Start the next receive Recv(); } void OnConnect( const std:: string & host, uint16_t port ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << host << ":" << port << std::endl; global_stream_lock.unlock(); // Start the next receive Recv(); std:: string str = "GET / HTTP/1.0\r\n\r\n" ; std::vector< uint8_t > request; std::copy( str.begin(), str.end(), std::back_inserter( request ) ); Send( request ); } void OnSend( const std::vector< uint8_t > & buffer ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << buffer.size() << " bytes" << std::endl; for ( size_t x = 0; x < buffer.size(); ++x ) { std::cout << std::hex << std::setfill( '0' ) << std::setw( 2 ) << ( int )buffer[ x ] << " " ; if ( ( x + 1 ) % 16 == 0 ) { std::cout << std::endl; } } std::cout << std::endl; global_stream_lock.unlock(); } void OnRecv( std::vector< uint8_t > & buffer ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << buffer.size() << " bytes" << std::endl; for ( size_t x = 0; x < buffer.size(); ++x ) { std::cout << std::hex << std::setfill( '0' ) << std::setw( 2 ) << ( int )buffer[ x ] << " " ; if ( ( x + 1 ) % 16 == 0 ) { std::cout << std::endl; } } std::cout << std::endl; global_stream_lock.unlock(); // Start the next receive Recv(); } void OnTimer( const boost::posix_time::time_duration & delta ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << delta << std::endl; global_stream_lock.unlock(); } void OnError( const boost::system::error_code & error ) { global_stream_lock. lock (); std::cout << "[" << __FUNCTION__ << "] " << error << std::endl; global_stream_lock.unlock(); } public : MyConnection( boost::shared_ptr< Hive > hive ) : Connection( hive ) { } ~MyConnection() { } }; int main( int argc, char * argv[] ) { boost::shared_ptr< Hive > hive( new Hive() ); boost::shared_ptr< MyConnection > connection( new MyConnection( hive ) ); connection->Connect( "www.google.com" , 80 ); while ( !_kbhit() ) { hive->Poll(); Sleep( 1 ); } hive->Stop(); return 0; } |
客户端代码简单的传送一个http GET协议到谷歌并且在命令行客户端以16进制格式输出。它的可重用的困难度度没有超过服务器,这意味
着服务端和客户端编程没有根本的不同。
通过网络封装,我们简化了很多工作。有很多特定网络封装的设计影响需要被注意。首先对于服务器,没有使用容器存储每个连接的概念
。这么做是因为如果存储所有连接到容器内,终端用户必须锁住容器来同步访问或者异步实现添加移除连接。总而言之,这是需要终端用
户实现的行为。不是所有网络程序必须同一时间处理所有连接,所以封装是最通用的办法。
接下来,所有连接的交互式通过一个专属的strand。strand对象运行事件按序列执行。那么我们就不必明确的锁定连接和事件,因为事件
将并发而无论线程的数量。如果用户使用了定制方案,那么用户需要按照同样的设计来实现自己的逻辑保证线程安全。
简单接收发送buffer逻辑是通过vector和list来实现的。任何有定制内存的需要将有自己特定的系统来进行处理,所以他们需要修改代码。对于简单的程序,提供系统已经足够处理,
最后封装设计并不适用每个人。这里仅仅是一个BOOST::ASIO的例子可能的扩展。请给予你的想法并且定制你的需求,最重要的一点就是熟悉你的boost::asio库
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步