boost教程(七):异步输入输出

每一部分都单独注释的,运行时取消注释,将其他部分注释起来就可以。

第一部分:IO服务与对象

/*

异步任务的典型例子是网络应用。 如果数据被发送出去了,比如发送至 Internet,通常需要知道数据是否发送成功。
如果没有一个象 Boost.Asio 这样的库,就必须对函数的返回值进行求值。 但是,这样就要求待至所有数据发送完毕,
并得到一个确认或是错误代码。 而使用 Boost.Asio,这个过程被分为两个单独的步骤:
第一步是作为一个异步任务开始数据传输。 一旦传输完成,不论成功或是错误,
应用程序都会在第二步中得到关于相应的结果通知。
主要的区别在于,应用程序无需阻塞至传输完成,而可以在这段时间里执行其它操作。

*/


/*
I/O 服务抽象了操作系统的接口,允许第一时间进行异步数据处理,而 I/O 对象则用于初始化特定的操作。
类 boost::asio::ip::tcp::socket 用于通过网络发送和接收数据,
类 boost::asio::deadline_timer 则提供了一个计时器,用于测量某个固定时间点到来或是一段指定的时长过去了。
*/

#include <boost/asio.hpp> 
#include <iostream> 

void handler(const boost::system::error_code &ec)
{
	std::cout << "5 s." << std::endl;
}


void handler1(const boost::system::error_code &ec)
{
	std::cout << "5 s." << std::endl;
}

void handler2(const boost::system::error_code &ec)
{
	std::cout << "10 s." << std::endl;
}

int test0()
{
	//I/O 服务 io_service,用于初始化 I/O 对象 timer。
	//boost::asio::io_service io_service;
	///*
	//就象 boost::asio::deadline_timer 那样,
	//所有 I/O 对象通常都需要一个 I/O 服务作为它们的构造函数的第一个参数。
	//第二个参数,用于表示在某个时间点或是在某段时长之后闹钟停止。
	//*/
	//boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(5));

	///*
	//通过调用方法 async_wait() 并传入 handler() 函数的名字作为唯一参数,可以让 Asio 启动一个异步操作。
	//我们只是传入了 handler() 函数的名字,而该函数本身并没有被调用。
	//async_wait() 的好处是,该函数调用会立即返回,而不是等待五秒钟。 
	//一旦闹钟时间到,作为参数所提供的函数就会被相应调用。
	//应用程序可以在调用了 async_wait() 之后执行其它操作,而不是阻塞在这里。
	//async_wait() 这样的方法被称为是非阻塞式的。
	//阻塞式的 wait() 方法,取代 boost::asio::deadline_timer 的调用。
	//由于它会阻塞调用,所以它不需要传入一个函数名,而是在指定时间点或指定时长之后返回。
	//*/
	timer.wait();
	//timer.async_wait(handler);

	///*async_wait() 会启动一个异步操作并立即返回,而 run() 则是阻塞的。因此调用 run() 后程序执行会停止。
	//个人感觉相当于下面的system("pause");
	//*/
	//io_service.run();





	boost::asio::io_service io_service;
	boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
	timer1.async_wait(handler1);
	boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(10));
	timer2.async_wait(handler2);
	/*
	 如果应用程序不应被阻塞,那么就应该在一个新的线程内部调用 run(),它自然就会仅仅阻塞那个线程。
	 一旦特定的 I/O 服务的所有异步操作都完成了,控制权就会返回给 run() 方法,然后它就会返回。
	 以上两个例子中,应用程序都会在闹钟到时间后马上结束。
	*/
	io_service.run();

	system("pause");
	return 0;
}

第二部分:可扩展性与多线程

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <iostream> 

void handler3(const boost::system::error_code &ec)
{
	std::cout << "5 s." << std::endl;
}

void handler4(const boost::system::error_code &ec)
{
	std::cout << "5 s." << std::endl;
}

//全局io服务
boost::asio::io_service io_service;
boost::asio::io_service io_service1;
boost::asio::io_service io_service2;
void run()
{
	//如果在某个 boost::asio::io_service 类型的对象之上调用 run() 方法,
	//则相关联的句柄也会在同一个线程内被执行。
	io_service.run();
}
void run1()
{
	io_service1.run();
}

void run2()
{
	io_service2.run();
}
int test1()
{
	//boost::asio::deadline_timer timer1(io_service, boost::posix_time::seconds(5));
	//timer1.async_wait(handler3);
	//boost::asio::deadline_timer timer2(io_service, boost::posix_time::seconds(5));
	//timer2.async_wait(handler4);
	///*
	// 如果第二个计时器触发时第一个仍在执行,则第二个句柄就会在第二个线程中执行。 
	// 如果第一个计时器的句柄已经终止,则 I/O 服务可以自由选择任一线程。
	//*/
	//boost::thread thread1(run);
	//boost::thread thread2(run);
	//thread1.join();
	//thread2.join();






	/*
	还有一个不同的方法:不要绑定多个线程到单个 I/O 服务,而是创建多个 I/O 服务。 
	然后每一个 I/O 服务使用一个线程。 如果 I/O 服务的数量与系统的处理器内核数量相匹配,
	则异步操作都可以在各自的内核上执行。
	******************

	在一定条件下使用多个 I/O 服务是有好处的,每个 I/O 服务有自己的线程,最好是运行在各自的处理器内核上,
	这样每一个异步操作连同它们的句柄就可以局部化执行。 每一个 I/O 服务就象一个小的自主应用。
	*/
	boost::asio::deadline_timer timer1(io_service1, boost::posix_time::seconds(5));
	timer1.async_wait(handler3);

	boost::asio::deadline_timer timer2(io_service2, boost::posix_time::seconds(5));
	timer2.async_wait(handler4);

	boost::thread thread1(run1);
	boost::thread thread2(run2);
	thread1.join();
	thread2.join();







	system("pause");
	return 0;
}

第三部分:网络编程

/*
网络功能是异步处理的一个很好的例子,因为通过网络进行数据传输可能会需要较长时间,
从而不能直接获得确认或错误条件。
Boost.Asio 提供了多个 I/O 对象以开发网络应用。 以下例子使用了 boost::asio::ip::tcp::socket
类来建立与另一台PC的连接,并下载 'Highscore' 主页;就象一个浏览器在指向 www.highscore.de 时所要做的。
*/


#include <boost/asio.hpp> 
#include <boost/array.hpp> 
#include <iostream> 
#include <string> 

boost::asio::io_service io_service3;

//域名解析器将网址翻译成相应的IP地址,对应的 I/O 对象是:boost::asio::ip::tcp::resolver。
/*
DNS服务器,其作用就象是电话本,它知晓哪个IP地址被赋给了哪台PC。 
由于这个过程本身的透明的,只要明白其背后的概念以及为何需要 boost::asio::ip::tcp::resolver I/O 对象就可以了。
域名解析不是发生在本地的,所以它也被实现为一个异步操作。 一旦域名解析成功或被某个错误中断,
resolve_handler() 函数就会被调用。
*/
boost::asio::ip::tcp::resolver resolver(io_service3);
boost::asio::ip::tcp::socket sock(io_service3);
boost::array<char, 4096> buffer;


/*
准确的字节数通过 std::size_t 类型的参数 bytes_transferred 给出。
*/
void read_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
	if (!ec)
	{
		/*
		如果是成功接收,则将数据写出至标准输出流。
		*/
		std::cout << std::string(buffer.data(), bytes_transferred) << std::endl;

		/*
		再次调用 async_read_some() 方法。 这是必需的,因为无法保证仅在一次异步操作中就可以接收到整个网页。
		async_read_some() 和 read_handler() 的交替调用只有当连接被破坏时才中止,
		*/
		sock.async_read_some(boost::asio::buffer(buffer), read_handler);
	}
}
/*
sock 也在 connect_handler() 的内部被使用,发送 HTTP 请求并启动数据的接收。 
因为所有这些操作都是异步的,各个句柄的名字被作为参数传递。
*/
void connect_handler(const boost::system::error_code &ec)
{
	if (!ec)
	{
		/*
		在该句柄的内部,会访问 ec 对象以检查连接是否已建立。 如果连接是有效的,
		则对相应的 socket 调用 async_read_some() 方法,启动读数据操作。
		*/
		boost::asio::write(sock, boost::asio::buffer("GET / HTTP 1.1\r\nHost: highscore.de\r\n\r\n"));
		/*
		每当有一个或多个字节被接收并保存至缓冲区时,read_handler() 函数就会被调用。
		*/
		sock.async_read_some(boost::asio::buffer(buffer), read_handler);
	}
}
/*
接收数据需要一个成功的连接,进而需要一次成功的域名解析,resolve_handler() 访问 I/O 对象 sock,
用由迭代器 it 所提供的解析后地址创建一个连接。
*/
void resolve_handler(const boost::system::error_code &ec, boost::asio::ip::tcp::resolver::iterator it)
{
	if (!ec)
	{
		/*
		调用了 async_connect() 方法之后,connect_handler() 会被自动调用。
		*/
		sock.async_connect(*it, connect_handler);
	}
}







boost::asio::io_service io_service4;
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 80);
// I/O 对象 acceptor - 被初始化为指定的协议和端口号 - 用于等待从其它PC传入的连接
boost::asio::ip::tcp::acceptor acceptor(io_service4, endpoint);
boost::asio::ip::tcp::socket sock1(io_service4);
std::string data = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, world!";

void write_handler(const boost::system::error_code &ec, std::size_t bytes_transferred)
{
}

void accept_handler(const boost::system::error_code &ec)
{
	if (!ec)
	{

		/*
		 async_write_some() 的方法也可以发送数据;不过它会在发送了至少一个字节之后调用相关联的句柄。
		 该句柄需要计算还剩余多少字节,并反复调用 async_write_some() 直至所有字节发送完毕。
		 而使用 boost::asio::async_write() 可以避免这些,因为这个异步操作仅在缓冲区的所有字节都被发送后才结束。
		*/
		boost::asio::async_write(sock, boost::asio::buffer(data), write_handler);
	}
}
int main()
{
	/*
	对象 query,表示一个查询, 这个查询被传递给 async_resolve() 方法以解析该名字。
	*/
	//boost::asio::ip::tcp::resolver::query query("www.highscore.de", "80");
	///*
	//域名解析的过程完成后,resolve_handler() 被调用,检查域名是否能被解析。
	//如果解析成功,则存有错误条件的对象 ec 被设为0。 只有在这种情况下,才会相应地访问 socket 以创建连接。
	//服务器的地址是通过类型为 boost::asio::ip::tcp::resolver::iterator 的第二个参数来提供的。
	//*/
	//resolver.async_resolve(query, resolve_handler);
	///*
	//main() 只要调用 I/O 服务的 run() 方法,将控制交给操作系统进行异步操作即可。
	//*/
	//io_service3.run();



	/*
	首先调用 listen() 方法将接收器置于接收状态,
	*/
	acceptor.listen();

	/*
	再用 async_accept() 方法等待初始连接。 用于发送和接收数据的 socket 被作为第一个参数传递。
	当一个PC试图建立一个连接时,accept_handler() 被自动调用。 如果该连接请求成功,
	就执行自由函数 boost::asio::async_write() 来通过 socket 发送保存在 data 中的信息。
	*/
	//有异常
	acceptor.async_accept(sock1, accept_handler);
	io_service4.run();



	system("pause");
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值