一、Socket创建和连接

C++网络编程(asio)


点击查看代码

1、Asio概述

​ Asio起源于Boost库,是一款专为网络I/O定时器串行端口通信设计的库,提供了同步和异步的编程模型,用以简化网络和低级I/O的操作。asio封装了操作系统一些底层机制如select、socket、poll/epoll等,以实现异步IO模型

Asio异步处理,可以使任务触发时不需要等待,继续往下执行其他任务,直至其它线程将处理完成,并回调通知此线程。

普通的网络编程,通常是指使用传统的系统调用和同步阻塞的方式进行网络通信,可以看看代码:
点击进入
其中的accept、recv、listen等函数默认是同步/阻塞的。

下面将使用Boost.Asio库对网络编程进行重写

2、网络编程基本流程

服务器端

  1. socket : 创建socket对象
  2. bind : 绑定本机ip+port
  3. listen : 监听。若监听到信号,建立连接
  4. accept : 接受客户端的连接请求,返回一个新的Socket对象用于与客户端通信。原因是现实中服务器对应多个客户端,每个客户端对应相应的socket对象进行收发信息
  5. read、write : 收发信息

客户端

  1. socket : 创建socket对象
  2. connect : 根据服务器ip+port,发送连接请求
  3. write、read : 发收信息

请添加图片描述## 1、创建终端节点

概念:所谓终端节点就是用来通信的端对端的节点,可以通过ip地址和端口构造,其他节点可以连接这个终端节点做通信.

客户端,我们可以通过对端(服务器端)的ip和端口构造一个endpoint,用这个endpoint和其通信。

int client_end_point() {
	std::string raw_ip_address = "127.0.0.1";
	unsigned short port_num = 3333;
	boost:system::error_code ec; // 错误码
	// asio提供转换地址
	asio::ip::address ip_address = asio::ip::address::from_string(raw_ip_address, ec);
	if (ec.value() != 0) {
		std::cout 
			<< "Failed to parse the IP Address. Error code = " 
			<< ec.value() << ". Message is " << ec.message();
		return ec.value();
	}

	// bind(ip+address)
	asio::ip::tcp::endpoint ep(ip_address, port_num);
	return 0;
}

此时,ep 对象表示客户端端点,可以用于连接指定的服务器上的 TCP。然而,代码并没有显示实际连接过程或与服务器的任何通信,因此它只是为将来使用而准备端点。

服务端,则只需根据本地地址绑定就可以生成endpoint

int server_end_point()
{
	unsigned short port_num = 3333;
	// 服务器将监听主机上的所有可用 IPv6 地址
	asio::ip::address ip_address = asio::ip::address_v6::any();
	asio::ip::tcp::endpoint ep(ip_address, port_num);
	return 0;
}

此时,ep 对象表示一个可以用于监听传入连接请求的 TCP 端点,其 IP 地址为所有可用的 IPv6 地址,而端口号由函数参数 port_num 决定。

2、创建socket

服务器和客户端socket一致,创建socket分为4步,

  1. 创建上下文io_context
  2. 选择协议
  3. 生成socket
  4. 打开socket
int create_tcp_socket()
{
	// 上下文告诉socket,此socket为ioc服务
	asio::io_context ioc;
	// IPV4的TCP协议
	asio::ip::tcp protocol = asio::ip::tcp::v4();
	asio::ip::tcp::socket socket(ioc);
	boost::system::error_code ec;

	socket.open(protocol, ec);
	if (ec.value() != 0) {
		std::cout 
			<< "Failed to open the socket. Error code = " 
			<< ec.value() << ". Message is " << ec.message();
	}

	return 0;
}

这段代码演示了如何使用 Boost.Asio 库来创建并打开一个 TCP 套接字

3、创建监听socket

服务端,我们还需要生成一个acceptorsocket,用来监听接收新来自客户端的连接

int create_acceptor_socket()
{
	asio::io_context ioc;
	asio::ip::tcp::acceptor a(ioc, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), 3333));
	return 0;
}

这段代码演示了如何使用 Boost.Asio 库来创建并打开一个监听套接字,用于接受传入的连接请求。监听套接字通常用于服务器端,用于等待客户端的连接。

4、绑定accpet监听套接字

对于accept类型的socket服务器要将其绑定到指定的断点,所有连接这个端点的连接都可以被接收到。

  • 创建端点(ip+端口)。
  • 创建监听套接字acceptor
  • 绑定监听套接字acceptor
int bind_acceptor_socket()
{
	unsigned short port_num = 3333;
	asio::ip::tcp::endpoint ep(asio::ip::address_v4::any(), port_num);
	asio::io_context ioc;
	asio::ip::tcp::acceptor acceptor(ioc, ep.protocol());
	boost::system::error_code ec;
	acceptor.bind(ep, ec);
	if (ec.value() != 0) {
		std::cout
			<< "Failed to bind the acceptor socket. Error code = "
			<< ec.value() << ". Message is " << ec.message();
	}
	return 0;
}

这段代码展示了如何使用 Boost.Asio 库创建一个绑定到指定 IP 地址和端口的监听套接字,用于等待客户端的连接请求。

5、连接指定的端点

作为客户端可以连接服务器指定的端点进行连接

  • 创建端点(ip+端口)。
  • 创建通信socket套接字。
  • 通信socket套接字连接到指定端点。
int connect_to_end()
{
	std::string raw_ip_address = "192.168.1.124";
	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 socket(ioc, ep.protocol());
		socket.connect(ep);
	}
	catch (system::system_error &e)
	{
		std::cout << "Error connect! Error code = " << e.code()
			<< ". Message: " << e.what();
		return e.code().value();
	}
	return 0;
}

这段代码用于在客户端创建套接字并连接到服务器,以便与服务器进行数据交换。

6、服务器接收连接

当有客户端连接时,服务器需要接收连接:

  • 创建端点(ip+端口)。
  • 创建监听套接字acceptor
  • 绑定监听套接字acceptor
  • 监听队列大小。
  • 创建与客户端通信套接字。
  • 接收客户端连接。
int accept_int_connection()
{
	// 缓冲来不及接收的信息
	const int BACKLOG_SIZE = 30;
	unsigned short port_num = 3333;
	asio::ip::tcp::endpoint ep(asio::ip::address_v4::any(), port_num);
	asio::io_context ioc;
	try
	{
		asio::ip::tcp::acceptor acceptor(ioc, ep.protocol());
		acceptor.bind(ep);
		acceptor.listen(BACKLOG_SIZE);
		asio::ip::tcp::socket socket(ioc);
		acceptor.accept(socket);
	}
	catch (system::system_error& e)
	{
		std::cout << "Error accept! Error code = " << e.code()
			<< ". Message: " << e.what();
		return e.code().value();
	}
	return 0;
}

这段代码用于在服务器端创建接受套接字,绑定端点并开始监听连接请求,然后处理下一个连接请求并与客户端建立连接,以便进行数据交换。


参考:
恋恋风辰blog
森明帮大于黑虎帮
哔哩哔哩

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值