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

摘要:
之前的篇章已经介绍了网络系统框架。我们只需要学习网络API函数即可我们首先学习如何同步的连接主机。我们的代码作为客户端运行,使用tcp::socket对象.tcp::socket对象针对不同协议有不同的socket类型.我们需要确认使用正确的对象。为了达到这个目标,我们使用tcp::resolver。#include#include#include#include#include#include#include#includeboost::mutexglobal_stream_lock;voidWorkerThread{global_stream_lock.lock();std::cout˂˂"["˂˂boost::this_thread::get_id()˂˂"]ThreadStart"˂run;if{global_stream_lock.lock();std::cout˂˂"["˂˂boost::this_thread::get_id()˂˂"]Error:"˂˂ec˂˂std::endl;global_stream_lock.unlock();}break;}catch{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()˂˂"]ThreadFinish"˂˂std::endl;global_stream_lock.unlock();}intmain{boost::shared_ptrio_service;boost::shared_ptrwork;boost::shared_ptrstrand;global_stream_lock.lock();std::cout˂˂"["˂˂boost::this_thread::get_id()˂˂"]Press[return]toexit."˂˂std::endl;global_stream_lock.unlock();boost::thread_groupworker_threads;for{worker_threads.create_thread;}boost::asio::ip::tcp::socketsock;try{boost::asio::ip::tcp::resolverresolver;boost::asio::ip::tcp::resolver::queryquery;boost::asio::ip::tcp::resolver::iteratoriterator=resolver.resolve;boost::asio::ip::tcp::endpointendpoint=*iterator;global_stream_lock.lock();std::cout˂˂"Connectingto:"˂˂endpoint˂˂std::endl;global_stream_lock.unlock();sock.connect;}catch{global_stream_lock.lock();std::cout˂˂"["˂˂boost::this_thread::get_id()˂˂"]Exception:"˂˂ex.what()˂stop();worker_threads.join_all();return0;}这个例子简单的开启了一个连接。程序将返回它实际尝试连接的端口和IP。如果我们开启一个命令提示窗口运行"netstat-n",我们会看见这个程序的TCP连接例子中我们使用query对象去重用这段代码。

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示例)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇array_map()与array_shift()搭配使用 PK array_column()函数oracle 中的truncate 和delete下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux 错误码对照表

errno 在 <errno.h> 中定义,错误 Exx 的宏定义在 /usr/include/asm-generic 文件夹下面的 errno-base.h 和 errno.h,分别定义了 1-34 、35-132 的错误定义。 strerror() 函数依据 errno 值返回错误描述字符串,下面程序打印对照表: #include <...

socket.io建立长连接

   socket.io是基于node.js,在命令行里输入npm socket.io下载模块,用node.js搭建后台 示例代码,客户端 1 <!DOCTYPE html> 2 <html lang="zh-CN"> 3 <head> 4 <meta charset="UTF-8"> 5...

node.js的net模块实现socket通信

本文实例讲述了通过node.js的net模块实现nodejs socket服务端和客户端简单通信功能,可以用作客户端对服务端的端口监听以及事件回执。 server端代码 var net = require('net'); //模块引入 var listenPort = 8080;//监听端口 var server = net.createServer(fu...

Unix套接字接口

简介 套接字是操作系统中用于网络通信的重要结构,它是建立在网络体系结构的传输层,用于主机之间数据的发送和接收,像web中使用的http协议便是建立在socket之上的。这一节主要讨论网络套接字。 套接字接口时一组函数,它们和Unix I/O结合起来,用于创建网络应用。许多操作系统都实现了自己的套接字接口。在Unix中,可以将套接字视为一个文件,使用文件I/...

DISPLAY变量和xhost(原创)

DISPLAY 在Linux/Unix类操作系统上, DISPLAY用来设置将图形显示到何处. 直接登陆图形界面或者登陆命令行界面后使用startx启动图形, DISPLAY环境变量将自动设置为:0:0, 此时可以打开终端, 输出图形程序的名称(比如xclock)来启动程序, 图形将显示在本地窗口上, 在终端上输入printenv查看当前环境变量, 输出结...

UVA 11404 简单LCS模型DP 字典序比较

这个题目求某个字符串中含的最长的回文子串。 就是一个很简单的LCS模型吗,而且我不明白为什么网上这么多人都说仿照某写法把字符串先逆序一下,然后求LCS,我只想问一下,有必要吗? 直接按LCS的套路来就行了啊,只不过方式变了下,按上面的写法,又麻烦,又根本没利用的LCS的精髓思想 即,先从间隔0位开始做起,然后是间隔1位。。2.。。n-1位,d[i][j]代...