尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
rust-libp2p UPnP 示例实战:通过网关自动对外映射端口获取公网地址
rust-libp2p UPnP 示例实战通过网关自动对外映射端口获取公网地址【免费下载链接】rust-libp2pThe Rust Implementation of the libp2p networking stack.项目地址: https://gitcode.com/GitHub_Trending/ru/rust-libp2p本篇基于 rust-libp2p 仓库中的examples/upnp示例完整讲解如何使用 libp2p 的 UPnP 网络行为upnp::tokio::Behaviour在支持 UPnP 的网络网关上自动打开端口并将本地监听地址转换为外部可达地址。读完后你将掌握该示例的运行方式、输出含义、事件处理逻辑以及底层门控gateway发现、端口映射续期与重试机制的源码实现细节。示例目标在网关上对外打开端口examples/upnp/README.md明确了示例的定位The upnp example showcases how to use the upnp network behaviour to externally open ports on the network gateway.也就是说当节点运行在 NAT 之后的局域网内时直接监听端口对外是不可达的。UPnPUniversal Plug and Play协议允许局域网内的程序通过 IGDInternet Gateway Device即支持 IGD 的路由器/网关远程添加端口映射。rust-libp2p 将该能力封装为libp2p-upnp行为节点启动后会自动寻找网关并把 swarm 的新监听地址映射为公网可达地址从而让远端节点可以主动拨入本节点。运行示例按照 README 的说明运行步骤如下进入示例目录在终端执行cargo run命令会启动 swarm并根据网关情况输出两种结果之一若网关支持 UPnP则打印NewExternalAddr获得外部可达地址若不支持则打印GatewayNotFound。该示例位于工作区中依赖声明见 examples/upnp/Cargo.toml其中通过upnpfeature 启用对应行为libp2p { path ../../libp2p, features [tokio, dns, macros, noise, ping, tcp, yamux, upnp] }对应地libp2p顶层 crate 的upnpfeature 映射到 libp2p/Cargo.toml 中的dep:libp2p-upnp而upnpfeature 又依赖tokiofeature 打开libp2p-upnp?/tokio。此外示例还接受一个可选的命令行参数若提供了第二个参数一个 multiaddressswarm 会主动拨号该地址见下文main.rs源码。示例源码逐段解读完整代码见 examples/upnp/src/main.rs核心结构如下let mut swarm libp2p::SwarmBuilder::with_new_identity() .with_tokio() .with_tcp( Default::default(), noise::Config::new, yamux::Config::default, )? .with_behaviour(|_| upnp::tokio::Behaviour::default())? .build(); // 在所有接口上监听随机端口端口 0 表示由操作系统分配。 swarm.listen_on(/ip4/0.0.0.0/tcp/0.parse()?)?; // 若第二个命令行参数是 multiaddress则拨号该对端。 if let Some(addr) std::env::args().nth(1) { let remote: Multiaddr addr.parse()?; swarm.dial(remote)?; println!(Dialed {addr}) } loop { match swarm.select_next_some().await { SwarmEvent::NewListenAddr { address, .. } println!(Listening on {address:?}), SwarmEvent::Behaviour(upnp::Event::NewExternalAddr { external_addr, local_addr: _, }) { println!(New external address: {external_addr}); } SwarmEvent::Behaviour(upnp::Event::GatewayNotFound) { println!(Gateway does not support UPnP); break; } SwarmEvent::Behaviour(upnp::Event::NonRoutableGateway) { println!( Gateway is not exposed directly to the public Internet, i.e. it itself has a private IP address. ); break; } _ {} } }要点行为层仅注册upnp::tokio::Behaviour::default()无需任何手工调用端口映射完全由 swarm 事件驱动自动完成监听地址固定为/ip4/0.0.0.0/tcp/0即所有接口、随机 TCP 端口——这正是 UPnP 需要映射的本地地址来源事件循环对upnp::Event的四个变体分别处理其中GatewayNotFound与NonRoutableGateway出现后直接break退出循环这与 README 所述“打印NewExternalAddr或GatewayNotFound”的行为一致。UPnP 行为的底层机制示例背后是libp2p-upnpcrateprotocols/upnp/Cargo.tomlcrate 名libp2p-upnp当前版本 0.7.0其文档注释在 protocols/upnp/src/lib.rs 中说明Implementation of UPnP port mapping for libp2p. This crate provides atokio::Behaviourwhich implements thelibp2p_swarm::NetworkBehaviourtrait. This struct will automatically try to map the ports externally to internal addresses on the gateway.网关发现与状态机行为主体Behaviour定义在 protocols/upnp/src/behaviour.rs。Behaviour::default()创建时立即启动网关搜索状态保存在GatewayState中共四种状态含义Searching正在搜索 IGD 网关持有一个 oneshot 接收端Available(Gateway)网关可用Gateway内含请求发送端、事件接收端和外部 IPGatewayNotFound未找到支持 UPnP 的网关NonRoutableGateway(IpAddr)网关存在但其外部 IP 不是公网地址如自身仍在 NAT 之后网关搜索逻辑在 protocols/upnp/src/tokio.rs 的search_gateway()中实现它tokio::spawn一个异步任务调用igd_next::aio::tokio::search_gateway(SearchOptions::default())发现网关随后get_external_ip()获取网关的公网 IP。之后该任务常驻持续把行为层发来的GatewayRequest::AddMapping/GatewayRequest::RemoveMapping转发给igd-next执行并把结果以GatewayEvent::Mapped/MapFailure/Removed/RemovalFailure回传。注意add_port调用中映射的名称字符串为rust-libp2p mapping可以在路由器管理页面的 UPnP 映射列表中识别出来。另一个关键判断是is_addr_global()protocols/upnp/src/tokio.rs网关返回的外部 IP 若落在私有、环回、链路本地、共享地址100.64.0.0/10等保留段内则认为网关本身未直接暴露在公网上行为进入NonRoutableGateway状态并发出Event::NonRoutableGateway事件——这正是示例打印“Gateway is not exposed directly to the public Internet”的来源。事件驱动的映射生命周期Behaviour的映射逻辑完全由 swarm 事件驱动on_swarm_eventprotocols/upnp/src/behaviour.rsFromSwarm::NewListenAddrswarm 每新增一个监听地址都会尝试映射。先经multiaddr_to_socketaddr_protocol()解析 multiaddr要求地址以私有 IPv4开头并封装Tcp(port)或Udp(port)协议否则直接跳过并记录 debug 日志——也就是说UPnP 行为只处理本机的私有 IPv4 TCP/UDP 监听地址源码注释标注 “Idg only supports Ipv4”。若同协议同端口已映射则去重跳过若此时网关仍在Searching该映射被记入add_requests状态为WaitingForGateway等网关可用后再统一补发若网关已Available则通过GatewayRequest::AddMapping立即请求若为GatewayNotFound或NonRoutableGateway请求被丢弃并记录 debug 日志FromSwarm::ExpiredListenAddr监听地址消失时若对应映射处于活跃状态则发起RemoveMapping清理并在收到网关确认后移除本地映射记录。映射参数与续期、重试策略protocols/upnp/src/behaviour.rs 顶部定义了一组常量决定了映射的保活与失败恢复策略常量值作用MAPPING_DURATION3600 秒在网关上注册端口映射的有效期MAPPING_TIMEOUT1800 秒续期定时器等于有效期的一半避免映射过期MAX_RETRY_ATTEMPTS5失败后的最大重试次数BASE_RETRY_DELAY_SECS30 秒指数退避基数实际延迟为30 × 2^retry_countMAX_RETRY_DELAY_SECS1800 秒单次重试延迟上限在poll中每条活跃映射都附带一个续期Delayrenew_mappings()在每次 poll 时检查定时器到期就重新向网关发起AddMapping以续期续期成功只刷新定时器不重复发出外部地址事件。映射失败时按上表做指数退避重试累计达到MAX_RETRY_ATTEMPTS后放弃并记录 warn 日志若失败的是已经活跃的映射即续期失败则发出Event::ExpiredExternalAddr并同步ToSwarm::ExternalAddrExpired让 swarm 层知晓该外部地址已失效。行为对外输出的事件Event枚举protocols/upnp/src/behaviour.rs定义了示例事件循环需要关注的四种信号事件含义示例中的处理NewExternalAddr { local_addr, external_addr }本地监听地址已在网关上成功映射external_addr为把 multiaddr 首段替换为网关公网 IP 后的外部地址打印New external address: ...ExpiredExternalAddr { local_addr, external_addr }某活跃映射续期失败外部地址不可达示例未显式处理落入_ {}GatewayNotFound未找到支持 UPnP 的 IGD 网关打印后退出NonRoutableGateway网关存在但未直接暴露到公网打印后退出外部地址的推导在Mapping::external_addr()中完成将监听 multiaddr 的第 0 段本地私有 IP替换为网关 IP支持 IPv4/IPv6 两种得到形如/ip4/公网IP/tcp/port的外部 multiaddr。测试对核心路径的验证behaviour.rs文件末尾内嵌了单元测试protocols/upnp/src/behaviour.rs用 mock 通道模拟网关覆盖了示例所依赖的关键路径new_mapping_then_removedNewListenAddr触发AddMapping→ 网关确认 → 映射进入活跃态监听地址过期触发RemoveMapping→ 确认后状态清空new_mapping_map_failure网关返回MapFailure时进入Failed重试状态retry_count: 1network_interface_change/network_interface_change_new_mapping_established模拟 Wi-Fi 切换有线等网络接口变更场景验证旧地址先移除、新地址再映射的完整状态迁移listener_with_multiple_addresses同一 listener 多个地址同端口不同 IP过期时仅首个触发RemoveMapping避免重复请求网关。这些测试与示例中事件循环处理的逻辑一一对应可以作为理解NewListenAddr/ExpiredListenAddr与网关请求交互关系的参照。适用前提与限制结合 README 与源码使用该示例以及libp2p-upnp行为需注意以下前提网关必须支持 UPnP/IGD示例运行在网关不支持 UPnP 的网络上时只会打印Gateway does not support UPnP并退出这属于预期行为而非错误双重 NAT 场景不可用若网关本身位于另一个 NAT 之后外部 IP 为私有地址行为会判定NonRoutableGateway此时获得的外部地址并不真正公网可达仅支持私有 IPv4 监听地址multiaddr_to_socketaddr_protocol()只接受以私有 IPv4 开头的 TCP/UDP multiaddrIPv6 监听地址或其他传输如 QUIC 的 UDP不会被该行为处理映射依赖运行环境igd-next通过 SSDP 发现网关实际能否成功add_port取决于路由器实现与 UPnP 是否被启用成功时映射会以rust-libp2p mapping名称出现在网关的端口映射列表中。综上examples/upnp以最小代码展示了 libp2p 获取公网入口的一种经典途径注册 UPnP 行为、监听本机地址然后从SwarmEvent::Behaviour(upnp::Event::NewExternalAddr)中拿到可对外宣告的地址。对于需要在 NAT 后提供可入站服务的 libp2p 节点这套“行为自动映射 事件自动续期/重试”的机制可以直接复用。【免费下载链接】rust-libp2pThe Rust Implementation of the libp2p networking stack.项目地址: https://gitcode.com/GitHub_Trending/ru/rust-libp2p创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

Flower 框架 Docker 部署:以子进程模式在 SuperLink/SuperNode 容器中运行 ServerApp 与 ClientApp

Flower 框架 Docker 部署:以子进程模式在 SuperLink/SuperNode 容器中运行 ServerApp 与 ClientApp

Flower 框架 Docker 部署:以子进程模式在 SuperLink/SuperNode 容器中运行 ServerApp 与 ClientApp 【免费下载链接】flower Flower: A Friendly Federated AI Framework 项目地址: https://gitcode.com/GitHub_Trending/flo/flower Flower 框架的 SuperLink…

📅 2026/9/17 10:26:33
6G服务化RAN:从基站拆分到端到端重构的演进之路

6G服务化RAN:从基站拆分到端到端重构的演进之路

简介:《2022年6G服务化RAN白皮书》由中国移动通信研究院发布,是一份面向通信研究者、网络架构师及高校通信专业师生的技术文献,系统回应了5G核心网已服务化但RAN仍以集成单体为主的发展痛点。白皮书提出基于云原生技术的端到端服务化RAN总体构…

📅 2026/9/17 10:26:33
SAR极化到底怎么选?一文讲清单极化、双极化与全极化

SAR极化到底怎么选?一文讲清单极化、双极化与全极化

把SAR的极化讲清楚,其实不需要搬出麦克斯韦方程组。我常跟团队里新来的同事打比方:你绷直一根绳子,握着一头上下甩,波就沿着绳子传出去;改成左右甩,传的还是同一根绳子,但“振动方向”完全不同。…

📅 2026/9/17 10:26:33
MORE NEWS

更多资讯

📰

Gutenberg 组件库中的 ToolbarDropdownMenu:让工具栏内的下拉菜单遵循 WAI-ARIA 键盘交互模式

Gutenberg 组件库中的 ToolbarDropdownMenu:让工具栏内的下拉菜单遵循 WAI-ARIA 键盘交互模式 【免费下载链接】gutenberg The Block Editor project for WordPress and beyond. Plugin is available from the official repository. 项目地址: https://gitcode.co…

📰

驱动电压布线实战:电机驱动PCB抗干扰设计与地弹抑制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

IDEA 2023创建Servlet项目全流程:Maven+Tomcat配置与实战

用 IDEA 2023 创建一个 Servlet 项目,这事看着简单,但真正动手时你就会发现,卡点往往不在 Servlet 代码本身,而在“项目怎么建、Tomcat 怎么配、依赖怎么引”这一串前置流程上。很多新手照着老教程走,结果 IDEA 版本不…

📰

PolarFlexBox:面向电机控制的混合式硬件在环实时验证平台

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

用DevTools破解Chrome小恐龙:JavaScript运行时调试实战指南

电脑断网的时候,我瞟了一眼Chrome右下角那只像素小恐龙,心里想的本来是“跑个几分就关了”。结果手太残,连两百分都没撑到,就在鸟和仙人掌之间反复去世。那会儿我越想越气,干脆打开开发者工具,做了一件所有…

📰

用Proteus玩转51单片机仿真:从环境搭建到交通灯实战

直接用Proteus玩转51单片机,这些年我用它做过交通灯、电子时钟、倒车雷达,甚至帮朋友调过电磁炉的控制逻辑。说实话,如果你正在学51单片机或者准备做课设,Proteus加Keil这套组合就是最省钱的硬件实验室。一块开发板少说几十块&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬