frp xtcp P2P 穿透详解:如何快速实现两台内网机器不走服务器中转的直连
【免费下载链接】frpA fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.项目地址: https://gitcode.com/GitHub_Trending/fr/frp
frp是一款高性能的反向代理内网穿透工具,其xtcp(P2P 打洞)模式可以让两台都藏在 NAT/防火墙后的内网机器建立点对点直连隧道——数据不再经过 frps 服务器中转,延迟更低、带宽不再受服务器限制。本文将带你快速理解 xtcp 的工作原理、完成两台内网机器的直连配置,并掌握隧道保活与回退等实用技巧。
一、为什么需要 xtcp:stcp 与 xtcp 的区别
frp 有两种"访问别人内网服务"的模式:
| 对比项 | stcp(Secret TCP) | xtcp(P2P 打洞) |
|---|---|---|
| 数据路径 | 访客 → frps 服务器 → 目标服务 | 访客 →直连隧道→ 目标服务 |
| 延迟 | 较高(多一跳) | 低(点对点) |
| 带宽占用 | 占用服务器带宽 | 几乎不占服务器带宽 |
| 成功率 | 高(只要服务器可达即可) | 取决于双方 NAT 类型 |
| 典型场景 | 远程访问内网 Web | 远程桌面、大流量低延迟需求 |
💡 一句话理解:stcp 把服务器当"传话人",xtcp 让双方自己"打电话",服务器只当"红娘"。
二、xtcp 是如何打通的:4 步握手流程
xtcp 的核心是一套UDP 打洞(NAT Hole Punching)机制,整个过程分为 4 步(对应源码 pkg/nathole/nathole.go):
1️⃣ STUN 探测与 NAT 类型识别
两台 frpc 客户端各自向公共 STUN 服务器发起探测,确认自己的公网映射地址,并判断 NAT 类型(EasyNAT / HardNAT)与端口映射行为(pkg/nathole/classify.go)。STUN 服务器默认使用stun.easyvoip.com:3478,可通过配置项natHoleStunServer覆盖(见 pkg/config/v1/client.go)。
2️⃣ 通过 frps 交换打洞信息
访客端(visitor)先做 PreCheck,确认目标代理在线;随后双方把各自的公网候选地址通过 frps 服务器交换(ExchangeInfo)。注意:这里服务器只转发少量元信息,不中转任何业务数据。
3️⃣ 同时发起 UDP 打洞
frps 根据双方 NAT 特征选择打洞策略(共 5 种 Detect Mode,覆盖 EasyNAT/EasyNAT、HardNAT/EasyNAT、HardNAT/HardNAT 等组合),指令双方在同一时刻向对方公网地址发送带 SID 的探测包(MakeHole),利用 NAT 的"回包放行"规则在防火墙上打出孔洞。
4️⃣ 建立 QUIC 或 KCP 隧道
孔洞打通后,双方在直连的 UDP 通道上建立QUIC(默认)或KCP隧道(见 client/visitor/xtcp.go)。之后访客访问本地绑定端口,数据就通过这条 P2P 隧道直达目标内网服务。
三、配置教程:三步实现内网直连
以下以"远程访问 A 机器的 22 端口(SSH)"为例,假设两台机器都运行 frpc,且都连接到同一台 frps。
步骤 1:A 机器(被访问方)配置 xtcp 代理
在 A 机器的 frpc 配置中添加 xtcp 类型代理(完整示例见 conf/frpc_full_example.toml):
[[proxies]] name = "p2p_tcp" type = "xtcp" secretKey = "abcdefg" localIP = "127.0.0.1" localPort = 22 allowUsers = ["user1"] # 不填则默认只允许同用户连接步骤 2:B 机器(访客方)配置 xtcp visitor
在 B 机器的 frpc 配置中添加 visitor,端口 9001 就是 B 本地能访问的入口:
[[visitors]] name = "p2p_tcp_visitor" type = "xtcp" serverName = "p2p_tcp" secretKey = "abcdefg" bindAddr = "127.0.0.1" bindPort = 9001 # 隧道保活与回退(可选) keepTunnelOpen = true maxRetriesAnHour = 8 minRetryInterval = 90步骤 3:连接使用
B 机器上执行ssh user@127.0.0.1 -p 9001,流量将经 P2P 隧道直达 A 机器的 SSH 服务。访客端源码逻辑见 client/visitor/xtcp.go:有隧道则复用,无隧道则阻塞等待打洞成功。
四、关键配置速查:保活、回退与打洞优化
| 配置项 | 所在侧 | 作用 |
|---|---|---|
keepTunnelOpen | visitor | 周期性探测并自动重建隧道,保持长连接可用 |
maxRetriesAnHour/minRetryInterval | visitor | 限制每小时重连次数、最小重连间隔,防止疯狂打洞 |
fallbackTo/fallbackTimeoutMs | visitor | 打洞失败/超时时自动回退到 stcp走服务器中转,保证可用性 |
protocol | visitor | 隧道协议,默认 QUIC,也可设为kcp |
natTraversal.disableAssistedAddrs | 两侧 | 禁用局域网辅助地址打洞,只用 STUN 发现的公网地址 |
🎯推荐做法:同时配置
keepTunnelOpen = true+fallbackTo = "stcp_visitor",直连优先、失败兜底,可用性接近 stcp,性能接近 P2P。
五、打洞失败怎么办:NAT 类型自查
xtcp 的成功率取决于 NAT 类型组合,双 HardNAT 时难度最大。可以用内置命令直接检测本机 NAT 特征(实现见 cmd/frpc/sub/nathole.go):
frpc nathole discover --nat_hole_stun_server stun.easyvoip.com:3478输出会显示 NAT 类型(EasyNAT/HardNAT)、端口映射行为与公网地址。经验法则:
- EasyNAT + EasyNAT:成功率最高,几乎必通;
- HardNAT + EasyNAT:需要端口猜测,一般可通;
- HardNAT + HardNAT:双方端口均随机变化时可能失败,建议配置
fallbackTo回退到 stcp。
服务器端如何撮合打洞会话、分析 NAT 特征,可参考 server/proxy/xtcp.go 与 pkg/nathole/controller.go;客户端打洞逻辑见 client/proxy/xtcp.go。
六、总结
frp 的 xtcp 模式通过STUN 探测 → 信息交换 → 同步 UDP 打洞 → QUIC/KCP 隧道四步握手,让两台内网机器绕过服务器建立直连,实现低延迟、高带宽的 P2P 访问。只需在两端分别配置type = "xtcp"的 proxy 和 visitor,配合keepTunnelOpen保活与fallbackTo回退,就能在享受直连性能的同时保证稳定可用。
【免费下载链接】frpA fast reverse proxy to help you expose a local server behind a NAT or firewall to the internet.项目地址: https://gitcode.com/GitHub_Trending/fr/frp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考