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,可能造成大量的分配操作,在某些环境下是不适用的。代码仅仅是用以教学目的。

#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

  

#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 );
} //-----------------------------------------------------------------------------

  

网络库尝试为可简便实现的客户服务端提供一个线程安全可扩展的封装。用户能够从基本连接继承定制类,连接器等。下面这个例子展示
了如何使用封装。
第一个例子我们将学习如何使用封装设置类。例子与上面的例子很类似,简单的回应所有连接。

#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线程,但是
提供了同样的功能。服务器运行正常,现在来查看客户端。

#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库

boost asio 学习(九) boost::asio 网络封装的更多相关文章

  1. boost asio 学习(一)io_service的基础

    原文  http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio/ 编译环境 b ...

  2. boost asio 学习(八) 网络基础 二进制写发送和接收

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=9 8. Net ...

  3. boost asio 学习(七) 网络基础 连接器和接收器(TCP示例)

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=8 7. Net ...

  4. boost asio 学习(六) 定时器

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=7 6 定时器 ...

  5. BOOST ASIO 学习专贴

    本文已于20170903更新完毕,所有boost asio 代码均为本人手抄.编译器为vs2013,并且所有代码已经上传,本文下方可下载源码 为了学习boost asio库,我是从boost的官方bo ...

  6. boost::asio::spawn 将一统C++网络库

    boost::asio::spawn 将一统C++网络库(金庆的专栏)boost::asio::spawn()创建一个协程,使C++网络编程大大简化,个人认为这使得 asio 成为C++首选网络库.b ...

  7. boost asio 学习(二)了解boost::bind

    2.了解boost::bind使用boost::bind封装一个函数,考虑以下例子示例2a #include <iostream> #include <boost/bind.hpp& ...

  8. boost::asio 学习草稿

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/ 可以多个线程拥有io_ ...

  9. boost asio 学习(五) 错误处理

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=6 5. Erro ...

随机推荐

  1. Groovy与Java集成常见的坑

    摘要: groovy特性 Groovy是一门基于JVM的动态语言,同时也是一门面向对象的语言,语法上和Java非常相似.它结合了Python.Ruby和Smalltalk的许多强大的特性,Groovy ...

  2. FastCGI点滴

    FastCGI是一种二进制协议,用于将交互式程序与Web服务器连接.它是早期通用网关接口(CGI)的变体.FastCGI的主要目标是减少与Web服务器和CGI程序之间的接口相关的开销,允许服务器每单位 ...

  3. 自然语言处理NLP-云端API汇总

    Google Google Cloud:https://cloud.google.com/natural-language/ ParallelDots ParallelDots, Inc. 无需训练, ...

  4. Java -- XStreamAlias 处理节点中的属性和值

    XStreamAlias 可以把objec和xml相互转换,但是有时候节点带有属性和值就需要特殊处理下: <?xml version="1.0" encoding=" ...

  5. scp: command not found

    scp 不能用? [root@doc]# scp jdk-8u144-linux-x64.tar.gz root@10.10.10.17:/root/ root@10.10.10.17's passw ...

  6. Python cx_Oracle 安装小记

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,Python cx_Oracle 安装小记 SQLAlchemy 是 Pytho ...

  7. 学习C++,应该循序渐进的看哪些书?

    在某博客上看到的一个C++书籍阅读清单,可以参考下: 阶段 1<Essential C++>这是一本内容不多但很实用的C++入门书籍,强调快速上手与理解C++编程.本书主要围绕一系列逐渐复 ...

  8. Android开发中常见的设计模式(四)——策略模式

    策略模式定义了一些列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变换. 假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等 ...

  9. 第二篇*2、Python字符串格式化

    1.字符串格式化 Python的字符串格式化有两种方式: 百分号方式.format方式 1)百分号方式 %[(name)][flags][width].[precision]typecode (nam ...

  10. Thinkphp语句拼接

    例如查询Stu表中年龄大于18,或者身高低于180cm的男性(1为男性),(例子不太好标题有可能不符,望见谅) $where['age'] = array("gt",18); $w ...