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的读写

时间: 2024-10-12 08:57:38

boost asio 学习(七) 网络基础 连接器和接收器(TCP示例)的相关文章

boost asio异步读写网络聊天程序客户端 实例详解

// // chat_client.cpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://ww

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网络方面的知识,我们可以尝试下封装网络底层.通过使用这个封装,我们可以重用代码并且将精力集中于业务逻 辑方面而不在网络通讯方面花费太多精力. 重要提示:本代码仅仅用于教学目的.不要在商业系统中使用该代码,

boost asio 学习(六) 定时器

http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=7 6 定时器 boost::asio 提供了一个 deadline_timer class来提供同步与异步的接口. BOOST文档提供了一组优秀示例.第一个例子,将创建一个间隔5秒的定时器. #include <boost/asio.hpp> #include <boost/shared_ptr.hpp&

boost asio 学习(三)

http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=4 本章节为io_service添加任务,并且区分dispatch与post的区别.如果说io_service是asio库的大脑,那么post与dispatch就是asio库的手和脚. 先看看示例1 #include <boost/asio.hpp> #include <boost/shared_ptr.hp

boost asio学习笔记 [1] - 同步通讯

本文以一段示例代码,说明使用boost asio进行同步通讯的使用方法. #include <iostream> #include <boost/asio.hpp> using namespace std; using boost::asio::ip::tcp;  int main() {     boost::asio::io_service   ioservice;             // I/O事件模型封装,如win下的iocp,unix下的poll, linux下的e

BOOST ASIO 学习专贴

1.同步使用Timer 本便使用了boost::asio::deadline_timer,这个timer有两种状态:过期和不过期.wait函数调用一个过期的timer直接返回. int _tmain(int argc, _TCHAR* argv[]) { boost::asio::io_service io; boost::asio::deadline_timer t(io,boost::posix_time::seconds(5)); t.wait(); std::cout<<"w

boost asio 学习(五) 错误处理

http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=6 5. Error handling 接下来我们需要注意的话题是错误处理.换句话说就是函数抛出异常时发生了什么 Boost::asio 给予用户两种选择来处理.错误通过handler传播,指出线程呼叫run或者poll系列函数的位置.用户可以能处理通过异常抛出的状态或者是接收返回的错误变量.更多关于BOOST的信息

boost::asio学习(定时器)

#include <boost/asio.hpp> #include <iostream> void handle1(const boost::system::error_code& ec) { std::cout << "5.s" << std::endl; } void handle2(const boost::system::error_code& ec) { std::cout << "10.

Boost.Asio学习笔记一、linux下boost库的安装

学习开源库的第一步就是,编译安装,然后我们才能写一写demo去测试. 所以本章我们学一下在linux编译安装Boost库,为了方便起见,直接安装完整库. 我使用的版本是boost_1_55_0,版本差别不大. [[email protected] ~]$ tar -zxvf boost_1_55_0.tar.gz [[email protected] boost_1_55_0]$ ./bootstrap.sh --prefix=/home/mjf/lib [[email protected] b