boost asio 学习 网络基础 连接器和接收器(TCP示例)
Posted itdef
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了boost asio 学习 网络基础 连接器和接收器(TCP示例)相关的知识,希望对你有一定的参考价值。
http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-
started-with-boostasio?pg=8
7. Networking basics: connectors and acceptors (TCP)
我们来学习boost的TCP网络编程。之前的篇章已经介绍了网络系统框架。我们只需要学习网络API函数即可
我们首先学习如何同步的连接主机。我们的代码作为客户端运行,使用tcp::socket对象.tcp::socket对象针对不同协议有不同的socket类型.我们需要确认使用正确的对象。当我们连接一个远端主机
,我们需要获得远端的地址。为了达到这个目标,我们使用tcp::resolver。
#include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <iostream> #include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl; global_stream_lock.unlock(); while( true ) { try { boost::system::error_code ec; io_service->run( ec ); if( ec ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Error: " << ec << std::endl; global_stream_lock.unlock(); } break; } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } } global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl; global_stream_lock.unlock(); } int main( int argc, char * argv[] ) { boost::shared_ptr< boost::asio::io_service > io_service( new boost::asio::io_service ); boost::shared_ptr< boost::asio::io_service::work > work( new boost::asio::io_service::work( *io_service ) ); boost::shared_ptr< boost::asio::io_service::strand > strand( new boost::asio::io_service::strand( *io_service ) ); global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Press [return] to exit." << std::endl; global_stream_lock.unlock(); boost::thread_group worker_threads; for( int x = 0; x < 2; ++x ) { worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) ); } boost::asio::ip::tcp::socket sock( *io_service ); try { boost::asio::ip::tcp::resolver resolver( *io_service ); boost::asio::ip::tcp::resolver::query query( "www.google.com", boost::lexical_cast< std::string >( 80 ) ); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ); boost::asio::ip::tcp::endpoint endpoint = *iterator; global_stream_lock.lock(); std::cout << "Connecting to: " << endpoint << std::endl; global_stream_lock.unlock(); sock.connect( endpoint ); } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } std::cin.get(); boost::system::error_code ec; sock.shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec ); sock.close( ec ); io_service->stop(); worker_threads.join_all(); return 0; }
这个例子简单的开启了一个连接。程序将返回它实际尝试连接的端口和IP。如果我们开启一个命令提示窗口运行 "netstat -n",我们会看见这个程序的TCP连接
例子中我们使用query对象去重用这段代码。代码更适用于数字而不是字符串,所以我们使用函数将端口从数字转化为字符串.
有时候我们可能需要异步的去连接一个远程主机.例如GUI程序通过一个按钮开启连接,但是我们不希望GUI界面在连接完成之前就冻结住。boost::asio提供了一个异步连接方式。
使用bind shared_ptr。
#include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <iostream> #include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl; global_stream_lock.unlock(); while( true ) { try { boost::system::error_code ec; io_service->run( ec ); if( ec ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Error: " << ec << std::endl; global_stream_lock.unlock(); } break; } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } } global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl; global_stream_lock.unlock(); } void OnConnect( const boost::system::error_code & ec, boost::shared_ptr< boost::asio::ip::tcp::socket > sock ) { if( ec ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Error: " << ec << std::endl; global_stream_lock.unlock(); } else { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Connected!" << std::endl; global_stream_lock.unlock(); } } int main( int argc, char * argv[] ) { boost::shared_ptr< boost::asio::io_service > io_service( new boost::asio::io_service ); boost::shared_ptr< boost::asio::io_service::work > work( new boost::asio::io_service::work( *io_service ) ); boost::shared_ptr< boost::asio::io_service::strand > strand( new boost::asio::io_service::strand( *io_service ) ); global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Press [return] to exit." << std::endl; global_stream_lock.unlock(); boost::thread_group worker_threads; for( int x = 0; x < 2; ++x ) { worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) ); } boost::shared_ptr< boost::asio::ip::tcp::socket > sock( new boost::asio::ip::tcp::socket( *io_service ) ); try { boost::asio::ip::tcp::resolver resolver( *io_service ); boost::asio::ip::tcp::resolver::query query( "www.google.com", boost::lexical_cast< std::string >( 80 ) ); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query ); boost::asio::ip::tcp::endpoint endpoint = *iterator; global_stream_lock.lock(); std::cout << "Connecting to: " << endpoint << std::endl; global_stream_lock.unlock(); sock->async_connect( endpoint, boost::bind( OnConnect, _1, sock ) ); } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } std::cin.get(); boost::system::error_code ec; sock->shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec ); sock->close( ec ); io_service->stop(); worker_threads.join_all(); return 0; }
如果想传递boost::asio对象,我们一般使用shared_ptr智能指针.因为大多数对象是不能拷贝的non-copyable,并且我们确定对象在等待调用期间依然有效。
我们使用bind设置我们的自定义处理程序。
最后一个例子我们异步连接远端地址
#include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <iostream> #include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Start" << std::endl; global_stream_lock.unlock(); while( true ) { try { boost::system::error_code ec; io_service->run( ec ); if( ec ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Error: " << ec << std::endl; global_stream_lock.unlock(); } break; } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } } global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Thread Finish" << std::endl; global_stream_lock.unlock(); } void OnAccept( const boost::system::error_code & ec, boost::shared_ptr< boost::asio::ip::tcp::socket > sock ) { if( ec ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Error: " << ec << std::endl; global_stream_lock.unlock(); } else { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Accepted!" << std::endl; global_stream_lock.unlock(); } } int main( int argc, char * argv[] ) { boost::shared_ptr< boost::asio::io_service > io_service( new boost::asio::io_service ); boost::shared_ptr< boost::asio::io_service::work > work( new boost::asio::io_service::work( *io_service ) ); boost::shared_ptr< boost::asio::io_service::strand > strand( new boost::asio::io_service::strand( *io_service ) ); global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Press [return] to exit." << std::endl; global_stream_lock.unlock(); boost::thread_group worker_threads; for( int x = 0; x < 2; ++x ) { worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) ); } boost::shared_ptr< boost::asio::ip::tcp::acceptor > acceptor( new boost::asio::ip::tcp::acceptor( *io_service ) ); boost::shared_ptr< boost::asio::ip::tcp::socket > sock( new boost::asio::ip::tcp::socket( *io_service ) ); try { boost::asio::ip::tcp::resolver resolver( *io_service ); boost::asio::ip::tcp::resolver::query query( "127.0.0.1", boost::lexical_cast< std::string >( 7777 ) ); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve( query ); acceptor->open( endpoint.protocol() ); acceptor->set_option( boost::asio::ip::tcp::acceptor::reuse_address( false ) ); acceptor->bind( endpoint ); acceptor->listen( boost::asio::socket_base::max_connections ); acceptor->async_accept( *sock, boost::bind( OnAccept, _1, sock ) ); global_stream_lock.lock(); std::cout << "Listening on: " << endpoint << std::endl; global_stream_lock.unlock(); } catch( std::exception & ex ) { global_stream_lock.lock(); std::cout << "[" << boost::this_thread::get_id() << "] Exception: " << ex.what() << std::endl; global_stream_lock.unlock(); } std::cin.get(); boost::system::error_code ec; acceptor->close( ec ); sock->shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec ); sock->close( ec ); io_service->stop(); worker_threads.join_all(); return 0; }
这个例子与上一个例子很类似。事实上仅仅有一点点改变。之前提到过,asio库是一个很优秀的库。我们学习他的一些组件,就能理解它的其他组件。
在端口7777上运行上面这段代码,我们可以从命令行窗口运行命令"telnet localhost 7777",开启一个到服务器的连接来激发代码中的 OnAccept函数
然而服务器将不能再接收更多的连接,这是因为我们仅仅只呼叫了async_accept一次并且只有一个socket 对象。稍后我们将处理服务器的设计策略。我们仅仅只是需要开启核心API。
例子中,我们使用错误变量来确认没有异常发生。
讨论完基本的连接和接收。下章节将讨论socket的读写
以上是关于boost asio 学习 网络基础 连接器和接收器(TCP示例)的主要内容,如果未能解决你的问题,请参考以下文章
boost asio 学习 boost::asio 网络封装
Boost::asio - 如何中断阻塞的 tcp 服务器线程?