boost::asio的Tcp同步方式

本文介绍如何使用Boost.Asio库实现TCP协议的同步读写操作,包括服务端和客户端的代码示例。通过创建io_service对象管理IO操作,使用socket对象进行通信。
部署运行你感兴趣的模型镜像

博文部分参考链接:https://www.cnblogs.com/lidabo/p/8317196.html

Boost.Asio是一个跨平台的网络及底层IO的C++编程库。

头文件

#include <boost/asio.hpp>

命名空间

using namespace boost::asio;
using boost::asio::ip::tcp;

ASIO库能够使用TCP、UDP、ICMP、串口来发送/接收数据,本文档介绍TCP协议的同步读写操作。

所有使用asio的程序都至少需要一个io_service 对象

boost::asio::io_service io_service;

服务端代码为:

#include <iostream>
#include <boost/asio.hpp>
using namespace boost::asio;

int main()
{
	typedef ip::tcp::acceptor acceptor_type;
	typedef ip::tcp::endpoint endpoint_type;
	typedef ip::tcp::socket socket_type;

	std::cout << "server.start." << std::endl;
	io_service io;		// asio程序必需的io_service对象

	acceptor_type acceptor(io, endpoint_type(ip::tcp::v4(), 8016));
	std::cout << "local address is: " <<
		acceptor.local_endpoint().address() << std::endl;

	try
	{
		while (true)
		{
			socket_type sock(io);
			acceptor.accept(sock);		// 阻塞等待socket连接

			std::cout << "client:";
			std::cout << sock.remote_endpoint().address() << std::endl;

			// 业务处理
			while (true)
			{
				char buf[128] = { 0 };
				boost::system::error_code ec;
				sock.read_some(buffer(buf), ec);
				std::cout << "buf is: " << buf << std::endl;
				memset(buf, 0, sizeof(buf)); // 将buf重置

				sock.write_some(buffer("hello client"), ec);
				if (ec)
				{
					std::cout << "system error is: " << 
						boost::system::system_error(ec).what() << std::endl;
					break;
				}
			}

		}
	}
	catch (const std::exception& ex)
	{
		std::cout << ex.what() << std::endl;
	}

	return 0;

}

客户端代码为:

#include <iostream>
#include <boost/asio.hpp>
#include <vector>
using namespace boost::asio;

int main(int argc, char* argv[])
{
	typedef ip::tcp::acceptor acceptor_type;
	typedef ip::tcp::endpoint endpoint_type;
	typedef ip::tcp::socket socket_type;
	typedef ip::address  address_type;

	io_service io;

	while (true)
	{
		try
		{
			std::cout << "client start." << std::endl;
			socket_type sock(io);  // socket对象

			// 连接端点,这里使用了本机连接,可以修改IP地址测试远程连接
			endpoint_type ep(address_type::from_string("127.0.0.1"), 8016); 

			boost::system::error_code ec;
			sock.connect(ep, ec); // 连接服务器
			std::cout << sock.available() << std::endl;

			// 如果出错,打印出错信息
			if (ec)
			{
				std::cout << boost::system::system_error(ec).what() << std::endl;
				return -1;
			}

			while (true)
			{
				// 收到数据
				char buf[128] = { 0 };
				std::cout << "please input: ";
				std::cin.getline(buf, 128);
				std::cout << std::endl;

				sock.write_some(buffer(buf), ec);

				memset(buf, 0, 128);	// 将buf重置
				sock.read_some(buffer(buf), ec);
				std::cout << "receive message is :" << buf << std::endl;

			}
		}
		catch (const std::exception& ex)
		{
			std::cout << ex.what() << std::endl;
		}
	}

	return 0;
}

演示如下:

 代码说明:

  • ASIO的TCP协议通过boost::asio::ip名 空间下的tcp类进行通信。
  • IP地址(address,address_v4,address_v6)、 端口号和协议版本组成一个端点(tcp:: endpoint)。用于在服务器端生成tcp::acceptor对 象,并在指定端口上等待连接;或者在客户端连接到指定地址的服务器上。
  • socket是 服务器与客户端通信的桥梁,连接成功后所有的读写都是通过socket对 象实现的,当socket析 构后,连接自动断 开。
  • ASIO读写所用的缓冲区用buffer函 数生成,这个函数生成的是一个ASIO内部使用的缓冲区类,它能把数组、指针(同时指定大 小)、std::vector、std::string、boost::array包装成缓冲区类。
  • ASIO中的函数、类方法都接受一个boost::system::error_code类 型的数据,用于提供出错码。它可以转换成bool测试是否出错,并通过boost::system::system_error类 获得详细的出错信息。另外,也可以不向ASIO的函数或方法提供 boost::system::error_code,这时如果出错的话就会直 接抛出异常,异常类型就是boost::system:: system_error(它是从std::runtime_error继承的)。

 

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

### `boost::asio::ip::tcp::acceptor` 的使用与问题解析 `boost::asio::ip::tcp::acceptor` 是 Boost.Asio 提供的一个用于 TCP 服务端监听和接受连接的核心组件。它封装了底层 socket 的绑定、监听和接受连接操作,简化了服务端的实现流程。 #### 初始化与绑定 在创建 `tcp::acceptor` 实例时,通常需要指定一个 `io_context` 对象和一个本地端点(`endpoint`),后者定义了绑定的 IP 地址和端口号。若未指定 IP 地址,则默认绑定到所有本地接口。例如: ```cpp boost::asio::ip::tcp::acceptor acceptor(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8080)); ``` 该操作会将 acceptor 绑定到 IPv4 的 8080 端口,并自动调用 `listen()` 进入监听状态。如果需要更细粒度的控制,可以显式调用 `listen()` 方法,并指定 backlog 值,该值决定了等待连接队列的最大长度。 #### 接受连接 `acceptor` 的核心功能是通过 `accept()` 方法接受新的客户端连接。该方法会阻塞当前线程,直到有新的连接到达。每次调用 `accept()` 都会返回一个新的 `tcp::socket` 对象,用于与客户端通信: ```cpp boost::asio::ip::tcp::socket socket(io_context); acceptor.accept(socket); ``` 在异步编程模型中,也可以使用 `async_accept()` 启动异步接受操作。该方法接受一个回调函数作为参数,当新连接到达时触发该回调函数执行后续处理: ```cpp acceptor.async_accept([&](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) { if (!ec) { // 处理新连接 } }); ``` 需要注意的是,异步接受操作必须在 `io_context.run()` 被调用的前提下才能正常执行。 #### 常见问题与解决方案 1. **绑定失败**:若端口已被占用或地址不可用,`acceptor` 初始化时会抛出异常。可以通过捕获 `boost::system::error_code` 或 `std::exception` 来处理错误: ```cpp boost::asio::ip::tcp::acceptor acceptor(io_context, endpoint, boost::asio::socket_base::reuse_address(true)); ``` 使用 `reuse_address(true)` 可以启用地址复用选项,避免因端口处于 TIME_WAIT 状态而无法绑定的问题。 2. **并发接受连接**:在高并发场景下,单个 `acceptor` 实例可能成为性能瓶颈。可以通过在多个线程中运行 `io_context.run()` 来提高并发处理能力,但需注意同步问题。另一种方式是使用 `fork()` 创建子进程处理新连接,但这增加了进程间通信的复杂性。 3. **异步操作生命周期管理**:使用 `async_accept()` 时,必须确保 `acceptor` 和 `io_context` 的生命周期足够长,否则可能导致异步操作未完成就被销毁,引发未定义行为。 4. **IPv4 与 IPv6 兼容性**:默认情况下,`acceptor` 只监听 IPv4 连接。若需支持 IPv6,应使用 `tcp::v6()` 构造端点,并确保操作系统支持 IPv6: ```cpp boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), 8080); ``` 5. **关闭 acceptor**:在服务端关闭时,应先调用 `close()` 方法释放资源,避免资源泄漏: ```cpp acceptor.close(); ``` #### 示例代码:异步 TCP 服务端 以下是一个使用 `tcp::acceptor` 实现的异步 TCP 服务端示例: ```cpp #include <boost/asio.hpp> #include <iostream> using boost::asio::ip::tcp; void handle_accept(const boost::system::error_code& ec, tcp::socket socket) { if (!ec) { std::cout << "New client connected!" << std::endl; // 可在此添加异步读写逻辑 } } int main() { try { boost::asio::io_context io_context; tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 8080)); for (;;) { tcp::socket socket(io_context); acceptor.async_accept([&](boost::system::error_code ec, tcp::socket socket) { handle_accept(ec, std::move(socket)); }); } io_context.run(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; } ``` 此示例展示了如何使用异步方式接受连接并处理客户端请求。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值