03. I/O 操作(异步)

1.以异步的方式向TCP socket中写入

Boost.asio提供的用于异步将数据写入套接字的最基本工具是Asio::ip::tcp::socket类的async_write_some()方法。其中一个方法的重载:

template<typename ConstBufferSequence,typename WriteHandler>
void async_write_some(const ConstBufferSequence & buffers,WriteHandler handler);

该方法启动写操作并立即返回。它接受一个对象,该对象表示一个缓冲区,其中包含要写入套接字的数据,作为其第一个参数。第二个参数是一个回调函数,该参数可以是函数指针、函子或满足WriteHandler概念要求的任何其他对象。
回调函数应该有以下签名:

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

这里,ec是一个参数,如果发生错误代码,则指示错误代码,bytes_transfer_参数指示在相应的异步操作期间已向套接字写入了多少字节。

正如async_write_some()方法的名称所暗示的那样,它启动了一个旨在将一定数量的数据从缓冲区写入套接字的操作。此方法保证在不发生错误的情况下,在相应的异步操作期间至少写入一个字节。这意味着,在一般情况下,为了将缓冲区中所有可用的数据写入套接字,我们可能需要多次执行此异步操作。

异步的调用此方法的步骤如下:

  1. 定义一个数据结构,其中包含一个指向套接字对象的指针、一个缓冲区和一个用作写入字节计数器的变量。
  2. 定义一个回调函数,该函数将在异步写入操作完成时调用。
  3. 在客户机应用程序中,分配并打开活动TCP套接字,并将其连接到远程应用程序。在服务器应用程序中,通过接受连接请求获得已连接的活动TCP套接字。
  4. 分配一个缓冲区,并用要写入套接字的数据填充它。
  5. 通过调用套接字的async_write_some()方法启动异步写入操作。指定步骤2中定义的函数作为回调函数。
  6. 在asio::io_service类的对象上调用run()方法。
  7. 在回调函数中,增加写入的字节计数器。如果写入的字节数小于需要写入的总字节数,则启动一个新的异步写操作来写入数据的下一部分。
#include <boost/asio.hpp>
#include <iostream>

using namesapce boost;

struct Session{
	std::shared_ptr<asio::ip::tcp::socket> sock;
	std::string buf;
	std::size_t total_bytes_written;
}//这个session类表示服务器端处理客户连接的管理类

void callback(const boost::system::error_code& ec, std::size_t bytes_transferred, std::shared_ptr<Session> s){
	if(ec != 0){
		std::cout<<"error occured! error code is"<<ec.value()<<".Message"<<ec.message();
		return;
	}
	s->total_bytes_written += bytes_transferred;
	
	if(s->total_bytes_written == s->buf.length()){
		return;
	}
	
	s->sock->async_write_some(
	asio::buffer(
	s->buf.c_str() +
	s->total_bytes_written,
	s->buf.length() -
	s->total_bytes_written),
	std::bind(callback, std::placeholders::_1,
	std::placeholders::_2, s));
}

void writeToSocket(std::shared_ptr<asio::ip::tcp::socket> sock){
	std::shared_ptr<Session> s(new Session);
	
	s->buf = std::string("hello");
	s->total_bytes_written = 0;
	s->sock = sock;
	
	s->sock->async_write_some(
	asio::buffer(s->buf),
	std::bind(callback,
	std::placeholders::_1,
	std::placeholders::_2,
	s));
}


int main(){
	std::string raw_ip_address = "192.168.3.10";
	unsigned short port_num = 3333;
	
	try{
		asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address),port_num);
		
		asio::io_context ioc;
		
		std::shared_ptr<asio::ip::tcp::socket> sock(new asio::ip::tcp::socket(ioc,ep.protocol()));
		
		sock->connect(ep);
		
		ioc.run();
	}catch(system::system_error &e){
		std::cout<<"error code = "<<e.code()<<".Message: "<<e.what();
		
	return e.code().value();
	}
	
	return 0;
}

777

posted @ 2024-09-07 13:07  yyyyyllll  阅读(26)  评论(0)    收藏  举报