C++ asio网络编程(3)asio socket同步读写

目录

同步写write_some

建立一个 TCP 连接,然后通过该连接发送数据

同步写send

同步写write

同步读read_some

作为socket把读的流程串联起来

同步读receive

同步读read


同步写write_some


同步写write_some,boost::asio提供了几种同步写的api,
 write_some可以每次向指定的空间写入固定的字节数,如果写缓冲区满了,就只写一部分,返回写入的字节数。

void write_to_socket(asio::ip::tcp::socket& sock)
{
	std::string buf = "Hello World";
	std::size_t total_byte_written = 0;
	//循环发送
	//write_some 返回每次写入的字节数
	//total_bytes_written是已经发送的字节数。
	//每次发送buf.length()- total_bytes_written)字节数据

	while (total_byte_written != buf.length()) {
		total_byte_written += sock.write_some(
			asio::buffer(buf.c_str() + total_byte_written,
				buf.length() - total_byte_written));
	}

}

配个图更通俗易懂

建立一个 TCP 连接,然后通过该连接发送数据

//建立一个 TCP 连接,然后通过该连接发送数据
int send_data_by_write_some() {
	std::string raw_ip_address = "192.168.3.11";
	unsigned short port_num = 3333;
	try {
		asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address), port_num);
		//创建了一个 TCP 终端点对象 ep,用于表示目标服务器的地址和端口。 
		//asio::io_service ios;

		asio::io_context ioc;
		//创建了一个 I/O 上下文对象 ioc,用于管理异步 I/O 操作。

		asio::ip::tcp::socket sock(ioc, ep.protocol());
		//创建了一个 TCP 套接字对象 sock,并将其与上下文 ioc 关联,以及与终端点 ep 关联。

		sock.connect(ep);
		//尝试通过套接字 sock 连接到目标服务器,即执行 TCP 连接操作

		write_to_socket(sock);
		//调用了一个名为 write_to_socket 的函数,该函数用于向套接字写入数据。

	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
	return 0;
	//如果出现系统错误,将会打印错误消息,其中包括错误代码和错误描述,
	//然后返回相应的错误代码值。如果一切顺利,函数将返回 0 表示成功。
	//整体来说,这段代码的作用是建立一个 TCP 连接,然后通过该连接发送数据。
}

同步写send

同步写sendwrite_some使用起来比较麻烦,需要多次调用,asio提供了send函数。
send函数会一次性将buffer中的内容发送给对端,
如果有部分字节因为发送缓冲区满无法发送,则阻塞等待,直到发送缓冲区可用,则继续发送完成。
 

//同步写sendwrite_some使用起来比较麻烦,需要多次调用,asio提供了send函数。
// send函数会一次性将buffer中的内容发送给对端,
// 如果有部分字节因为发送缓冲区满无法发送,则阻塞等待,直到发送缓冲区可用,则继续发送完成。
int send_data_by_send() {
	std::string raw_ip_address = "192.168.3.11";
	unsigned short port_num = 3333;
	try {
		asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address), port_num);
		//asio::io_service ios;
		asio::io_context ioc;
		asio::ip::tcp::socket sock(ioc, ep.protocol());
		sock.connect(ep);
		std::string buf = "Hello World!";

		int send_length = sock.send(asio::buffer(buf.c_str(),buf.length()));
		//asio::buffer(buf.c_str(), buf.length()): 这里使用 asio::buffer 函数将字符串转换为 Boost.Asio 缓冲区对象。
		// asio::buffer 函数接受指向数据的指针和数据的长度作为参数,并返回一个表示数据的缓冲区对象。

		//sock.send 是 Boost.Asio 库中用于通过套接字发送数据的函数。
		// 它的作用是将指定的数据发送到已连接的远程端点(通常是另一个计算机上的网络服务)。
		//sock.send(...): 这是通过 Boost.Asio 套接字对象 sock 发送数据的操作。
		// 在这里,将使用 send 函数向连接的对端发送数据。
		// 作为参数传递给 send 函数的是要发送的数据的缓冲区对象。
		
		//int send_length = ...: 将发送的数据的长度存储在整型变量 send_length 中。
		// send_length 变量将会接收 send 函数返回的结果,即实际发送的数据的字节数。

		if (send_length <= 0) {
			return 0;
		}
		//如果发送的数据长度小于等于 0,这可能表示发送过程中出现了错误或者没有发送任何数据。因此,通过检查 send_length 的值,
		// 如果发现数据发送长度小于等于 0,代码会立即返回 0,表示发送操作失败或者没有发送任何数据。
	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
	return 0;
}

同步写write

在 Boost.Asio 中,除了使用套接字对象的 send 函数来发送数据外,还可以使用 asio::write 函数来发送数据。下面是关于 asio::write 的说明:

  • SyncWriteStream:表示支持同步写操作的流对象,通常是一个套接字对象。
  • ConstBufferSequence:表示要发送的数据的缓冲区序列。

asio::write 函数将指定的数据序列写入到给定的流对象中,对于套接字对象来说,即发送数据到远程端点。与 send 函数不同的是,asio::write 函数会一直尝试写入所有数据,直到所有数据都被写入或者发生错误。

int send_length = asio::write(sock, asio::buffer(buf.c_str(), buf.length())) 这行代码使用了 asio::write 函数来发送字符串 buf 中的数据,并将实际发送的数据长度存储在 send_length 变量中。这个操作与之前介绍的 sock.send 函数实现的功能类似,只是使用了不同的函数接口。

//同步写write,类似send方法,asio还提供了一个write函数,可以一次性将所有数据发送给对端,
// 如果发送缓冲区满了则阻塞,直到发送缓冲区可用,将数据发送完成。
int send_data_by_write() {
	std::string raw_ip_address = "192.168.3.11";
	unsigned short port_num = 3333;
	try {
		asio::ip::tcp::endpoint ep(asio::ip::address::from_string(raw_ip_address), port_num);
		//asio::io_service ios;
		asio::io_context ioc;
		asio::ip::tcp::socket sock(ioc, ep.protocol());
		sock.connect(ep);
		std::string buf = "Hello World!";
		int send_length = asio::write(sock, asio::buffer(buf.c_str(), buf.length()));
		//asio::write 函数将指定的数据序列写入到给定的流对象中,对于套接字对象来说,
		// 即发送数据到远程端点。与 send 函数不同的是,
		// asio::write 函数会一直尝试写入所有数据,直到所有数据都被写入或者发生错误。
		//在使用 asio::write 函数时,你需要提供要写入的流对象(通常是套接字对象)
		// 以及表示要发送的数据的缓冲区序列。函数会阻塞当前线程,直到所有数据都被写入或者发生错误。
		//总的来说,asio::write 提供了一种方便的方式来将数据写入到同步写流对象中
		// 它对于发送数据到套接字非常有用,同时也简化了发送数据的操作。
		if (send_length <= 0) {
			return 0;
		}

	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
	return 0;
}

同步读read_some

同步读和同步写类似,提供了读取指定字节数的接口read_some

//同步读read_some,同步读和同步写类似,提供了读取指定字节数的接口read_some
std::string read_from_socket(asio::ip::tcp::socket& sock) {
	const unsigned char MESSAGE_SIZE = 7;
	char buf[MESSAGE_SIZE];
	std::size_t total_byte_read = 0;
	while (total_byte_read != MESSAGE_SIZE) {
		total_byte_read += sock.read_some(asio::buffer(buf + total_byte_read,
			MESSAGE_SIZE - total_byte_read));
	}

	return std::string(buf, total_byte_read);
}

作为socket把读的流程串联起来

//作为socket把读的流程串联起来
int read_data_by_read_some() {
	std::string raw_ip_address = "127.0.0.1";
	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;
		asio::ip::tcp::socket sock(ioc, ep.protocol());
		sock.connect(ep);
		read_from_socket(sock);
        //注意此read_from_socket(sock)是上面那个代码段,我们自定义的函数
	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
}

同步读receive

可以一次性同步接收对方发送的数据

//同步读receive,可以一次性同步接收对方发送的数据
int read_data_by_receive() {
	std::string raw_ip_address = "127.0.0.1";
	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;
		asio::ip::tcp::socket sock(ioc, ep.protocol());
		sock.connect(ep);
		const unsigned char BUFF_SIZE = 7;
		char buffer_receive[BUFF_SIZE];
		int receive_length = sock.receive(asio::buffer(buffer_receive,BUFF_SIZE));
		//在 Boost.Asio 中,sock.receive 函数用于从套接字接收数据。
		//两个参数:buffer:要接收数据的缓冲区对象,可以使用 asio::buffer 来创建。
		//flags:可选的附加标志参数,默认为0,表示无特殊标志。
		// 
		//sock.receive 函数将从已连接的远程端点接收数据,并将接收到的数据存储在指定的缓冲区中。
		// 它是一个同步操作,会阻塞当前线程直到数据接收完成或者出现错误。
		//函数会返回实际接收的字节数,如果发生错误则返回一个特定的错误码。
		// 你可以通过检查返回的字节数来确定实际接收到了多少数据。
		//在使用 sock.receive 函数时,你需要提供一个缓冲区对象来存储接收到的数据,
		// 并可以选择是否使用附加的标志参数。接收到的数据将会被存储在指定的缓冲区中,供后续处理和分析。
		//总的来说,sock.receive 函数是用于从套接字接收数据的方法,
		// 它允许你接收远程端点发送过来的数据,并将其存储在指定的缓冲区中。

		if (receive_length <= 0) {
			std::cout << "receive failed!"<< std::endl;
		}
	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
}

同步读read

可以一次性同步读取对方发送的数据

//同步读read,可以一次性同步读取对方发送的数据
int read_data_by_read() {
	std::string raw_ip_address = "127.0.0.1";
	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;
		asio::ip::tcp::socket sock(ioc, ep.protocol());
		sock.connect(ep);
		const unsigned char BUFF_SIZE = 7;
		char buffer_receive[BUFF_SIZE];
		int receive_length = asio::read(sock,asio::buffer(buffer_receive, BUFF_SIZE));
		//在 Boost.Asio 中,asio::read 是用于从流对象(例如套接字)中读取数据的函数。
		//SyncReadStream:表示支持同步读操作的流对象,通常是一个套接字对象。
		//MutableBufferSequence:表示用于存储接收数据的可变缓冲区序列。
		//asio::read 函数将从给定的流对象中读取数据,并将其存储在指定的缓冲区中。
		// 与 receive 函数不同的是,asio::read 函数会一直尝试读取指定数量的数据,直到所有数据都被读取或者发生错误。
		//在使用 asio::read 函数时,你需要提供要读取的流对象(通常是套接字对象),
		// 以及用于存储接收数据的可变缓冲区序列。函数会阻塞当前线程,直到指定数量的数据被读取或者发生错误。
		//asio::read 函数返回实际读取的字节数,如果发生错误则返回一个特定的错误码。你可以通过检查返回的字节数来确定实际读取了多少数据。
		//总的来说,asio::read 提供了一种方便的方式来从流对象中读取数据,对于接收套接字中的数据非常有用,同时也简化了读取数据的操作。

		if (receive_length <= 0) {
			std::cout << "receive failed!" << std::endl;

		}
	}
	catch (system::system_error& e) {
		std::cout << "Error occured!Error code=" << e.code()
			<< ".Message:" << e.what();

		return e.code().value();
	}
}

读取直到指定字符

我们可以一直读取,直到读取指定字符结束

std::string  read_data_by_until(asio::ip::tcp::socket& sock) {
    asio::streambuf buf;
 
    asio::read_until(sock, buf, '\n');
    std::string message;
    //由于缓冲区 'buf' 可能包含 '\n' 符号之后的其他数据,
    //我们需要解析缓冲区并提取出分隔符之前字符。 

    std::istream input_stream(&buf);
    std::getline(input_stream, message);
    return message;
 }

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值