当前位置: 首页 > news >正文

Endpoint

在 Boost.Asio 中,端点(Endpoint) 是网络通信中用于标识 “通信一端” 的核心组件,本质是IP 地址与端口号的组合(如 127.0.0.1:1234)。它在网络操作中扮演 “地址标签” 的角色:无论是 TCP 客户端连接服务器、TCP 服务器绑定端口,还是 UDP 收发数据,都需要通过端点明确 “与谁通信” 或 “在哪个地址 / 端口上通信”。

一、端点的核心定位与分类

Boost.Asio 的端点是对网络地址的抽象,其核心作用是:

  • 唯一标识网络中的一个通信节点(如服务器的 IP + 端口、客户端的临时 IP + 端口);
  • 为 socket 操作(连接、绑定、发送、接收)提供目标地址或本地地址信息;
  • 适配不同的网络协议(TCP/UDP)和地址族(IPv4/IPv6)。

根据协议类型,Boost.Asio 中最常用的端点类分为:

端点类对应协议地址族支持典型用途
boost::asio::ip::tcp::endpointTCPIPv4(tcp::v4())、IPv6(tcp::v6()TCP 客户端连接服务器、TCP 服务器绑定监听端口
boost::asio::ip::udp::endpointUDP同上UDP 发送数据到目标、UDP 接收数据时标识来源

二、端点的底层基础:basic_endpoint 模板

tcp::endpoint 和 udp::endpoint 并非完全独立的类,而是基于模板类 basic_endpoint<Protocol> 的特化。其中,Protocol 是协议类型(如 tcp 或 udp),它决定了端点支持的地址族和协议特性。

basic_endpoint 的核心定义可简化为:

template <typename Protocol>
class basic_endpoint {
public:// 协议类型(如tcp、udp)typedef Protocol protocol_type;// 构造函数:通过地址和端口创建端点basic_endpoint(const typename Protocol::address_type& addr, unsigned short port);// 获取/设置地址(IP地址)typename Protocol::address_type address() const;void address(const typename Protocol::address_type& addr);// 获取/设置端口号unsigned short port() const;void port(unsigned short port);// 获取协议(如tcp::v4())protocol_type protocol() const;// 转换为字符串(如"127.0.0.1:1234")std::string to_string() const;
};

tcp::endpoint 和 udp::endpoint 分别是 basic_endpoint<tcp> 和 basic_endpoint<udp> 的别名,因此它们的接口完全一致,仅协议类型不同。

三、端点的创建与初始化

端点的核心是 “IP 地址” 和 “端口号”,创建端点的关键是正确指定这两个信息。Boost.Asio 提供了多种创建方式,适应不同场景。

1. 基于 “地址对象 + 端口” 创建

最常用的方式是先构造 IP 地址对象(ip::address 或 ip::address_v4/ip::address_v6),再结合端口号创建端点。

  • IPv4 端点

    #include <boost/asio.hpp>
    namespace asio = boost::asio;
    using asio::ip::tcp;
    using asio::ip::udp;// 创建IPv4地址(127.0.0.1)
    asio::ip::address_v4 ipv4_addr = asio::ip::address_v4::from_string("127.0.0.1");
    // 基于IPv4地址和端口1234创建TCP端点
    tcp::endpoint tcp_ep_v4(ipv4_addr, 1234);
    // 基于同样的地址和端口创建UDP端点
    udp::endpoint udp_ep_v4(ipv4_addr, 1234);
    
  • IPv6 端点

    // 创建IPv6地址(::1,本地回环)
    asio::ip::address_v6 ipv6_addr = asio::ip::address_v6::from_string("::1");
    // 创建IPv6的TCP端点(端口5678)
    tcp::endpoint tcp_ep_v6(ipv6_addr, 5678);
    
2. 基于 “协议族 + 端口” 创建(自动绑定地址)

若不需要指定具体 IP 地址(如服务器绑定到 “所有本地地址”),可通过协议族(tcp::v4() 或 tcp::v6())直接创建端点,此时地址会自动设为 “通配地址”(0.0.0.0 for IPv4,:: for IPv6)。

// TCP服务器绑定到所有IPv4地址的1234端口(通配地址)
tcp::endpoint tcp_server_ep(tcp::v4(), 1234); 
// UDP服务器绑定到所有IPv6地址的5678端口
udp::endpoint udp_server_ep(udp::v6(), 5678);

通配地址的作用:服务器通常需要监听所有本地网卡的 IP(如服务器有多个网卡时),通配地址可实现这一需求(客户端连接时会自动匹配对应的网卡 IP)。

3. 从字符串解析创建(from_string

通过 endpoint::from_string 静态方法,可直接从 “IP: 端口” 格式的字符串解析出端点(需注意协议类型匹配)。

// 从字符串解析TCP端点(IPv4)
tcp::endpoint tcp_ep = tcp::endpoint::from_string("192.168.1.1:8080");// 从字符串解析UDP端点(IPv6)
udp::endpoint udp_ep = udp::endpoint::from_string("[::1]:9090"); // IPv6需用[]包裹地址

注意:IPv6 地址在字符串中需用 [] 包裹(如 [2001:db8::1]:80),否则无法正确解析端口。

4. 从底层套接字地址创建(高级)

对于需要直接操作操作系统底层套接字地址(如 sockaddr_in for IPv4)的场景,可通过 basic_endpoint 的构造函数转换:

// 底层IPv4套接字地址(sockaddr_in)
sockaddr_in native_addr;
native_addr.sin_family = AF_INET;
native_addr.sin_port = htons(1234); // 端口(网络字节序)
inet_pton(AF_INET, "127.0.0.1", &native_addr.sin_addr); // IP地址// 从底层地址创建TCP端点
tcp::endpoint tcp_ep(reinterpret_cast<sockaddr*>(&native_addr), sizeof(native_addr));

四、端点的核心成员函数

tcp::endpoint 和 udp::endpoint 提供了一致的接口,用于获取和修改端点信息,常用函数如下:

1. 获取 / 设置 IP 地址:address()
  • address():返回当前端点的 IP 地址(类型为 ip::address,可兼容 IPv4 和 IPv6)。
  • address(const ip::address&):修改端点的 IP 地址。
tcp::endpoint ep(tcp::v4(), 1234);
// 获取IP地址(此时为通配地址0.0.0.0)
asio::ip::address addr = ep.address(); 
std::cout << "原地址:" << addr.to_string() << "\n"; // 输出 "0.0.0.0"// 修改为127.0.0.1
ep.address(asio::ip::make_address("127.0.0.1"));
std::cout << "新地址:" << ep.address().to_string() << "\n"; // 输出 "127.0.0.1"
2. 获取 / 设置端口号:port()
  • port():返回当前端点的端口号(主机字节序,如 1234)。
  • port(unsigned short):修改端点的端口号(传入主机字节序,底层会自动转换为网络字节序)。
udp::endpoint ep(udp::v4(), 80);
std::cout << "原端口:" << ep.port() << "\n"; // 输出 80ep.port(443); // 修改端口为443
std::cout << "新端口:" << ep.port() << "\n"; // 输出 443
3. 获取协议类型:protocol()

返回端点关联的协议(tcp::v4()tcp::v6()udp::v4() 或 udp::v6()),用于判断端点的协议族和类型。

tcp::endpoint tcp_ep(tcp::v6(), 1234);
if (tcp_ep.protocol() == tcp::v6()) {std::cout << "这是IPv6的TCP端点\n";
}
4. 转换为字符串:to_string()

将端点转换为 “IP: 端口” 格式的字符串(IPv6 地址会自动用 [] 包裹),方便日志输出或调试。

tcp::endpoint ipv4_ep(asio::ip::make_address("192.168.1.1"), 8080);
std::cout << ipv4_ep.to_string() << "\n"; // 输出 "192.168.1.1:8080"udp::endpoint ipv6_ep(asio::ip::make_address("2001:db8::1"), 9090);
std::cout << ipv6_ep.to_string() << "\n"; // 输出 "[2001:db8::1]:9090"

五、端点在网络操作中的典型应用

端点是 socket 操作的 “地址参数”,几乎所有网络通信步骤都需要端点参与,以下是典型场景:

1. TCP 服务器:绑定本地端点并监听

TCP 服务器需通过 tcp::acceptor 绑定到本地端点(指定 IP 和端口),才能接受客户端连接:

asio::io_context io;
// 本地端点:IPv4,端口1234(通配地址,监听所有本地网卡)
tcp::endpoint local_ep(tcp::v4(), 1234); 
// 创建acceptor并绑定到本地端点
tcp::acceptor acceptor(io, local_ep); // 接受客户端连接(客户端的端点会通过socket.remote_endpoint()获取)
tcp::socket client_socket(io);
acceptor.accept(client_socket);
std::cout << "客户端连接:" << client_socket.remote_endpoint().to_string() << "\n";
2. TCP 客户端:连接服务器端点

TCP 客户端需指定服务器的端点(IP + 端口),通过 socket.connect() 建立连接:

asio::io_context io;
tcp::socket socket(io);
// 服务器端点:127.0.0.1:1234
tcp::endpoint server_ep(asio::ip::make_address("127.0.0.1"), 1234);
// 连接服务器
socket.connect(server_ep);
3. UDP 发送:指定目标端点

UDP 是无连接协议,发送数据时需通过 send_to 明确目标端点(对方的 IP + 端口):

asio::io_context io;
udp::socket socket(io); // 客户端不绑定端口(系统自动分配)
// 目标服务器端点:127.0.0.1:5678
udp::endpoint server_ep(asio::ip::make_address("127.0.0.1"), 5678);
// 发送数据到目标端点
std::string msg = "Hello UDP";
socket.send_to(asio::buffer(msg), server_ep);
4. UDP 接收:获取发送方端点

UDP 接收数据时,通过 receive_from 获取发送方的端点(以便回复或识别来源):

asio::io_context io;
// 本地端点:绑定到IPv4的5678端口(服务器)
udp::endpoint local_ep(udp::v4(), 5678);
udp::socket socket(io, local_ep);char buf[1024];
udp::endpoint sender_ep; // 用于存储发送方端点
// 接收数据,并获取发送方端点
size_t len = socket.receive_from(asio::buffer(buf), sender_ep);
std::cout << "从 " << sender_ep.to_string() << " 收到:" << std::string(buf, len) << "\n";// 回复发送方(使用sender_ep作为目标)
socket.send_to(asio::buffer("收到"), sender_ep);

六、关键注意事项

  1. 地址族匹配:端点的地址族(IPv4/IPv6)必须与 socket 的协议族一致,否则会导致操作失败(如用 IPv6 端点连接 IPv4 socket)。

    // 错误示例:IPv6端点连接IPv4 socket
    tcp::socket socket(io, tcp::v4()); // socket是IPv4的
    tcp::endpoint ep(tcp::v6(), 1234); // 端点是IPv6的
    socket.connect(ep); // 会返回错误(地址族不匹配)
    
  2. 端口有效性:端口号范围是 0~65535,其中 0~1023 是知名端口(需管理员权限),1024~49151 是注册端口,49152~65535 是动态端口(客户端通常用动态端口)。

  3. 通配地址的特殊性:服务器绑定到通配地址(0.0.0.0 或 ::)时,local_endpoint().address() 返回的是通配地址,而非实际的网卡 IP(实际 IP 需通过客户端连接的 remote_endpoint 反推)。

  4. 值类型特性:端点是值类型(可复制、赋值),而非引用类型,因此在函数间传递时会复制,无需担心生命周期问题(与 socket 的引用语义不同)。

总结

Boost.Asio 的端点(tcp::endpoint/udp::endpoint)是网络地址的抽象,通过 “IP 地址 + 端口号” 唯一标识通信节点,是所有 socket 操作的基础参数。其核心特点是:

  • 适配 TCP/UDP 协议和 IPv4/IPv6 地址族,接口统一;
  • 支持多种创建方式(地址 + 端口、协议族 + 端口、字符串解析等);
  • 提供丰富的接口用于获取 / 修改地址和端口,方便调试和配置。
http://www.dtcms.com/a/511995.html

相关文章:

  • 阿里巴巴双11微服务智能监控体系:从全链路追踪到AI自愈的技术实践
  • 在ros2 humble版本上安装D455相机并获取图像和深度信息
  • C++DirectX9坐标系与基本图元之渲染状态(RenderState)_0304
  • 网站建设app长春seo技术
  • 【C++】力扣hot100错误总结
  • C++中的vector讲解
  • 笔记【字符串,转义字符,注释】
  • visual studio安装本地帮助手册
  • 北京市基础建设质量监督局网站wordpress 插件怎么看
  • 大模型技术分析与演进逻辑
  • 苏州模板网站建站长沙网站建设推广
  • 从零起步学习MySQL || 第六章:MySQL数据库中的一条数据是如何存储的?(结合源码深度解析)
  • 微信小程序页面配置,基本语法,页面切换,tabbar全局配置
  • 数据结构 07
  • 18.基本的ACL
  • 网站后台编程语言创业中文网站模板
  • 从“刘易斯拐点”到“骑手拐点”,即时零售3.0时代还有多远?
  • 有没有一种app类似网站建设开发定制软件开发
  • 沈阳网站建设建设公司普洱网站建设
  • 蓝桥杯题库——部分简单题题解(Java)
  • 新民电商网站建设程序wordpress淘宝发货插件
  • 多服务隔离部署jenkins自动化脚本:从构建到上线的全流程保障
  • React JSX完全指南
  • CSS进阶 | 不用一行JS!用纯CSS打造会动的现代化单页应用(3D翻转卡片)
  • 云栖重磅|瑶池数据库:从云原生数据底座向“AI就绪”的多模态数据底座演进
  • LeetCode 410.分割数组的最大值
  • python批量读取word表格写入excel固定位置
  • 区块链知识总结
  • 开关电源三种拓扑资料整理
  • xss-labs pass-07