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。
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 | #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。
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 | #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设置我们的自定义处理程序。
最后一个例子我们异步连接远端地址
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 | #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的读写
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话