zoukankan      html  css  js  c++  java
  • 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的读写

  • 相关阅读:
    iOS11自定义tabBar重影问题
    iOS打包时遇到的has one iOS Distribution certificate but its private key is not installed的问题
    MAC本地生成SSH KEY的方法
    Mac版Sourcetree的安装使用
    Xcode报错:could not attach to pid:"1764"
    解决Xcode10 Library not loaded: /usr/lib/libstdc++.6造成的crash及报错
    socket调试工具(Mac版)
    iOS-基于TCP连接<Scoket-服务端>
    iOS自定义TabBar使用popToRootViewControllerAnimated返回后tabbar重叠
    [UIApplication sharedApplication].keyWindow.rootViewController
  • 原文地址:https://www.cnblogs.com/itdef/p/5619859.html
Copyright © 2011-2022 走看看