×

p2p通信原理——STUN 协议详解

hqy hqy 发表于2026-04-17 15:32:16 浏览12 评论0

抢沙发发表评论

在中文互联网上检索一些 STUN  的解析资料,但是发现基本都基于 RFC 3489 (2003) 讲解,新一点的是 RFC 5389 (2008) ,包括对 NAT  类型的探测也还停留在对称型,完全锥形那一套。所以写下这篇文章,对最新的 STUN 标准 RFC 8489 (2020) 进行一个解析。

大家都知道 IPv4 协议事实上只有  2 32  数量(大概四十亿)的 IP 地址,早在上个世纪就面临了 IP 地址紧缺的问题。于是计算机科学家们设计了 NAT ,通过多台设备共享一个 IP 地址,缓解了 IP 紧缺的问题,并延续至今。

而伴随着NAT的出现,一个问题又浮出水面。一个 NAT 内部设备怎么与另一个 NAT 内部设备进行通信?

如果你了解 TCP/UDP  等等的协议的话,就知道 NAT 实际上是对这些协议的端口进行映射,把内部主机的端口映射到 NAT 上。但是这个映射通常是短暂的,甚至因为不同的NAT实现,同一个主机端口可能映射到不同的 NAT 端口或地址之上。

最初的解决方案是 RFC 3489 —— STUN (Simple Traversal of User Datagram Protocol (UDP)Through Network Address Translators (NATs)) 一个简单的基于 UDP 进行 NAT 穿越通信的工具。

但是 RFC 3489 毕竟只是一个 Simple 的玩具,不足以应用于诸多复杂的生产环境,比如对 NAT 类型进行的归类 (full core, restricted cone, port restricted cone, symmetric ) 并不能够完全描述现实中存在的 NAT 设备行为。

于是重新设计了 RFC 5389 —— STUN (Session Traversal Utilities for NAT)。从一个 Simple Traversal 简单的穿越 变成了 Session Traversal Utilities 会话穿越工具集。而 RFC 8489 只是在 RFC 5389 的基础上增加了一些补充,比如新协议支持,额外的安全保障等等。

STUN 下有很多的工具,比如:

  • RFC 5780: NAT 行为发现 (NAT Behavior Discovery)

  • RFC 8445: 交互式连接建立 (ICE -- Interactive Connectivity Establishment )

  • RFC 8656: 基于中继的 NAT 穿越 (TURN -- Traversal Using Relays around NAT)

  • ......

本文只打算讲解 RFC 8489 (基本的协议构成), RFC 5780 中对 NAT 各种行为探测,还有一些简单的 NAT 穿越方案。

什么是 NAT ?

前文中我们已经了解到 NAT 是 IPv4 地址短缺问题的一个解决方案,那它是如何解决的呢?

NAT 全称 Network Address Translation ,直译过来就是网络地址转换。NAT 的工作也正如他的名字一样,就只是转换 IP 地址。以 UDP 为例,一个典型的 NAT 设备拥有一个公网 IP 地址 1.1.1.1,同时维护一个子网, NAT 在子网中的地址为 192.168.0.1。现在有一个终端 A ,想要通过 NAT 设备与互联网进行通信,子网为它分配了地址 192.168.0.2。那么对于 A 来说,它只需要将 NAT 设备 192.168.0.1 当做它的默认网关(接入互联网的第一个路由器)。

终端 A 使用端口 1145 发送 UDP 数据包到 1.2.3.4:1145,默认网关也就是 NAT 设备在接收来自终端 A 的数据包以后,会篡改数据包的 IP 头的来源地址 192.168.0.2 为自己的公网 IP 1.1.1.1,接着篡改 UDP 头的端口为 11451,也就是将 192.168.0.1:1145 映射到 1.1.1.1:11451。接着再继续转发到自己的默认网关,直到数据包到达 1.2.3.4

如下图所示:

在 1.2.3.4:1145 眼里看来,终端 A 其实就是 1.1.1.1:11451。而 NAT 在接收到数据包时只需要检查数据包的信息根据先前建立的映射表转发给终端 A 就好了。

是的,这时你可能已经发现了一个问题,NAT 内部的终端如果要访问另一个终端时,需要通过公网 IP 定位才能与对方通信,显然如果对方位于 NAT 内部时,地址信息都是没有暴露出来的。

那怎么才能使俩个 NAT 内部的设备进行通信呢?聪明的你可能已经想到一个办法了 ——— 如果我有办法获取某个终端在他的 NAT 上映射的地址,那么另一个 NAT 内部的终端直接与该地址进行通信不就好了?那么只需要用一个拥有公网地址的中间人去获取某个终端在其 NAT 上映射的地址。

这个中间人就是最早的 STUN 服务器雏形。

一些 NAT 穿越的猜想

见以下流程:

NAT A 下有一个终端 END A,其拥有一个公网地址 IP A ;NAT B 下有一个终端 END B,其拥有一个公网地址 IP B ;在公网存在一个 STUN 服务器 STUN SERVER

  • END A 尝试与 STUN SERVER 建立 UDP 连接,于是 NAT A 便将该连接绑定到 IP A:PORT A 上,STUN SERVER 便可从发来的 IP 数据包中解析出对应 IP A:PORT A

  • END B 尝试与 STUN SERVER 建立 UDP 连接,于是 NAT B 便将该连接绑定到 IP A:PORT B 上,STUN SERVER 便可从发来的 IP 数据包中解析出对应 IP B:PORT B

接着 STUN SERVER 将 END A 的地址 IP A:PORT A 发送给 END B,将 END B 的地址 IP B:PORT B 发送给 END A

最后 END A 或 END B 互相发送 Hello 消息,并检查对方地址是否正确。这样便可以进行通信啦。

不过理想很丰满,现实很骨感。现实中的 NAT 行为非常古怪难以琢磨,并不像上面一样老老实实的映射。比如 END B 尝试给 IP A:PORT A 发送信息时,NAT A 发现这个数据包的地址以前从来没有访问过,怀疑 END B 是 hacker,直接给你丢弃了,这个好解决,用刚才的办法相互不断重试发送 Hello 消息就好了。

但是还有更奇怪的,END A 尝试给不同的地址发送数据,不同的终端地址在 NAT A 上映射的地址都不一样,比如 END A 给 END B 发送消息时映射的地址不是 IP A:PORT A 而是 IP X:PORT X,可他们都是 END A 使用同一个端口发送的(这里会有不同的 IP 原因是一个 NAT 可以拥有不止一个公网 IP)。同端口同目的地的 UDP 与 TCP 连接映射也不一样

甚至 NAT 上面可能还有其他的 NAT。怎么办?

那就需要根据 NAT 的不同行为来选择对应的通信手段了,于是便有了 NAT 行为发现,对 NAT 的各种行为进行探测归类,针对不同类型实施不同 NAT 穿越方案。最早的归类来自 RFC 3489 ,把 NAT 抽象成了四类:

  • full core

  • restricted cone

  • port restricted cone

  • symmetric

后来发现这些并不能完全对 NAT 进行归类,于是便有了 RFC 5780 (NAT Behavior Discovery Using STUN)

RFC 5780 是一个实验性的标准,不过我也没想明白为什么一个实验性的标准用了十几年还在实验。

RFC 5780 是基于 STUN 的,接下来将对 STUN RFC 8489 进行一个简单的概述。

STUN 简介

典型 STUN 应用场景在前文已经进行讲述了,大概如下图:

在 RFC 8489 中提供的模型中 STUN Server 也可以拥有 NAT ,这里简化了一下模型。

STUN 是一种客户端-服务器协议,支持两种事务类型:

  1. 请求/响应事务(request/response transaction),客户端发送请求,服务器返回响应
    client server
    client server

  2. 指示事务(indication transaction),仅包含一个单向指示消息,无需响应
    client server

同样的也是一种应用层协议,目前可以运行在 UDP / TCP / TLS-over-TCP / DTLS-over-UDP 四种传输层协议上,当然不同传输层会有不同的完整性保证。

消息结构

STUN 消息采用二进制编码,使用网络/大端字节序。其传输顺序在 RFC 791 的 附录 B 中有详细描述。

一个 STUN 消息一般由一个固定长度的头部和若干属性组成,这些属性都是 T-L-V (类型-长度-值) 的结构。如下图所示:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   0|0 0|     STUN Message Type     |         Message Length        |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  32|                         Magic Cookie                          |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  64|                                                               |
    |                     Transaction ID (96 bits)                  |
    |                                                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 128|                           Attribute 1                         |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 160|                           Attribute 2                         |
    |                                                               |
    |                                                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 256|                           Attribute 3                         |
    |                                                               |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                             Attr……                            |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

每个 STUN 消息的 最高两位必须为 0。这可以在STUN 复用端口时用于区分 STUN 数据包和其他协议数据包。

STUN Message Type

消息类型(STUN Message Type)字段定义了 STUN 消息的类别(requestsuccess response, error responseindication)以及消息方法 message method 。

虽然说 STUN 消息有四种,但其实只是对两种事务类型进行更加详细的划分

  • requestsuccess response, error response :属于请求/响应事务,把响应划分为成功和失败俩种,以便更好的处理消息。

  • indication:属于指示事务。

消息方法目前来说只定义了一种 Binding,以后可能会有多的。

STUN 消息类型结构如下所示:

                        0                 1
                        2  3  4 5 6 7 8 9 0 1 2 3 4 5

                       +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
                       |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
                       |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
                       +--+--+-+-+-+-+-+-+-+-+-+-+-+-+

在消息类型字段中,位的排列方式如下:

M11-M0:12 位,表示 STUN 消息方法。
C1、C0:2 位,表示消息类别:

  • 00 : request

  • 01 : indication

  • 10 : success response

  • 11 : error response

例如,

  • Binding 请求:类别 00(请求),方法 000000000001(Binding),编码值:0x0001

  • Binding 成功响应:类别 10(成功响应),方法 000000000001(Binding),编码值:0x0101

注意:这种编码方式来源于RFC 3489,当时并未考虑指示、成功响应和错误响应需要单独编码。

Magic Cookie

该字段必须包含固定值 0x2112A442(网络字节序)。

在 RFC 3489 中,该字段曾是事务 ID 的一部分。将魔法 Cookie 置于此位置,可以帮助服务器检测客户端是否支持本规范新增的属性,并帮助区分 STUN 数据包和其他协议数据包(当 STUN 与其他协议复用端口时)。

Transaction ID

事务 ID 是一个 96 位(12 字节)的唯一标识符,在  [ 0 , 2 96 1 ]  的范围内均匀随机选择,用于标识 STUN 事务。

在请求/响应事务中,事务 ID 由客户端生成,将请求与响应关联,也就是每个相关的请求/响应事务的 ID 一样的;在指示事务中,事务 ID 由发送指示消息的对象生成,没啥用就是调试用。

相同请求的重新发送将重用相同的事务 ID,但客户端必须为新事务选择新的事务 ID,除非新请求与前一个请求完全相同并从相同的传输地址发送到相同的 IP 地址。成功和错误响应必须携带与其对应请求相同的事务 ID。

Message Length

消息长度包含消息的字节大小,但不包括 20 字节的 STUN 头部,也就是后面属性的长度。

由于所有 STUN 属性都填充为 4 字节的倍数,因此消息长度字段的最后 2 位始终为 0,这提供了一种额外的方法来区分 STUN 数据包与其他协议数据包。

Attributes

每个属性都是 T-L-V (类型-长度-值)编码格式,32 位对齐,且字段均以大端字节序传输,如下图:

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |         Type                  |            Length             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         Value (variable)                ....
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

属性(Type)字段被划分为两个范围。 - 0x0000 - 0x7FFF: 必须理解属性,这意味着 STUN 代理如果不理解该属性,将无法成功处理消息; - 0x8000 - 0xFFFF: 可选理解属性,这意味着如果 STUN 代理不理解这些属性,可以将其忽略。

长度(Lenth)字段表示值的实际字节数(不含填充)。若值长度非 4 字节的倍数,需在尾部填充 1-3 字节的任意值以满足对齐要求,填充内容可被忽略。

在 STUN 消息中,任何属性类型可以出现多次。除非另有说明,属性的出现顺序是有意义的:接收方只需要处理第一次出现的该属性,其余重复出现的属性可以被忽略

因为篇幅限制,所以只取一些后面会用到的属性进行介绍(好吧其实是偷懒)

XOR-MAPPED-ADDRESS

XOR-MAPPED-ADDRESS 属性功能与 MAPPED-ADDRESS (兼容 RFC 3489 的属性) 相同,用于表示客户端的反射传输地址(NAT 上映射的地址)。它由一个 8 位的地址族和一个 16 位的端口组成,后跟一个固定长度的值表示 IP 地址,并通过 XOR 运算进行了混淆。

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |x x x x x x x x|    Family     |         X-Port                |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                X-Address (Variable)
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

前 8 位必须设置为 0,为了 32 位对齐。

Family 表示 IP 地址族,如果地址族为 IPv4,则地址必须为 32 位;如果地址族为 IPv6,则地址必须为 128 位。所有字段均须采用网络字节序。

X-Port:将主机的端口号与 Magic Cookie 的高 16 位异或后转为网络字节序。

X-Address:

  • IPv4:取映射的 IP 地址(以主机字节序表示)与魔术字异或后转为网络字节序。

  • IPv6:取映射的 IP 地址(以主机字节序表示)与魔术字及 96 位事务 ID 拼接值异或后转为网络字节序。

对于属性值的前 8 位的编码和处理规则、处理属性多次出现的规则以及地址族的处理规则,与 MAPPED-ADDRESS 完全相同。

XOR-MAPPED-ADDRESS 与 MAPPED-ADDRESS 仅在传输地址的编码方式上有所不同。前者通过将传输地址与 magic cookie 进行异或运算来编码,而后者则直接以二进制方式编码。RFC 3489 最初仅规定了 MAPPED-ADDRESS,但实际部署经验发现,一些 NAT 会重写包含 NAT 公网 IP 地址的 32 位二进制负载(如 STUN 的 MAPPED-ADDRESS 属性),这种出于提供通用 ALG 功能的善意但错误的尝试,会干扰 STUN 的正常运行,并导致 STUN 的消息完整性检查失败。

CHANGE-REQUEST

CHANGE-REQUEST 属性包含两个标志位,用于控制服务器发送响应时使用的 IP 地址和端口。这两个标志分别称为“更改 IP”(change IP)和“更改端口”(change port)标志。

该属性长度为 32 位,其中仅使用了两个比特(A 和 B):

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

各标志的含义如下:

  • A(change IP):若为 true,则请求服务器使用 与接收到绑定请求时不同的 IP 地址 发送绑定响应。

  • B(change port):若为 true,则请求服务器使用 与接收到绑定请求时不同的端口 发送绑定响应。

OTHER-ADDRESS

OTHER-ADDRESS 属性与 MAPPED-ADDRESS 属性结构是一样的。它由一个 8 位的地址族和一个 16 位的端口组成,后跟一个固定长度的值表示 IP 地址。

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |0 0 0 0 0 0 0 0|    Family     |           Port                |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |                 Address (32 bits or 128 bits)                 |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

前 8 位必须设置为 0,为了 32 位对齐。

Family 表示 IP 地址族,如果地址族为 IPv4,则地址必须为 32 位;如果地址族为 IPv6,则地址必须为 128 位。Address 则表示对应的地址族 IP 地址。所有字段均须采用网络字节序。

OTHER-ADDRESS 中包含的地址为 —— 如果客户端在请求里包括 CHANGE-REQUEST 并设置 "change IP" 或 "change port",那么服务器将会使用的源 IP 地址和端口。

NAT 行为发现

在 RFC 5780 中不选择直接对 NAT 进行归类,而是针对某一个特性进行检测,使用者可以根据这些特性选择应该适合的通信方式。大概的检测步骤如下:

  1. 确定 NAT 映射行为(Determining NAT Mapping)

  2. 确定 NAT 过滤行为(Determining NAT Filtering)

  3. 绑定生存期发现(Binding Lifetime Discovery)

  4. 诊断 NAT 回环(Diagnosing NAT Hairpinning)

  5. 确定 NAT 对数据包分片的处理方式(Determining Fragment Handling)

  6. 检测 NAT 设备的通用应用层网关(ALG)(Detecting a Generic Application Level Gateway, ALG)

出于篇幅限制,仅仅讲解比较重要的前俩个步骤。

1.确定 NAT 映射行为

RFC 4787 中对 NAT 映射行为分为了三类:

  • Endpoint-Independent Mapping (EIM)
    对于相同的 (内部IP, 内部端口),无论目标地址是谁,NAT 都会使用相同的 (外部IP, 外部端口)。

  • Address-Dependent Mapping (ADM)
    NAT 会依据目标 IP 地址为 (内部IP, 内部端口) 分配不同的外部端口。即同一个内部地址,连接不同外部 IP 时使用不同的外部端口。

  • Address and Port-Dependent Mapping (APDM)
    更严格,NAT 会依据目标 IP 和端口决定映射。每个 (目的IP, 目的端口) 都会生成一个新的映射。

此过程最多需要进行三次测试:

  1. 测试 I:客户端执行 UDP 连接性测试。收到绑定响应(Binding Response)后客户端检查 XOR-MAPPED-ADDRESS 属性:
    - 如果该地址和端口与客户端用于发送请求的本地 IP 和端口相同,则表明客户端未经过NAT(或者 NAT 没有做地址转换),此时映射行为可以认为端点独立映射(Endpoint-Independent Mapping),否则执行测试 II。
    - 服务器将在绑定响应(Binding Response)中的 OTHER-ADDRESS 字段返回备用地址和端口。如果 OTHER-ADDRESS 字段未返回,表示服务器不支持此功能,无法进行进一步测试。

  2. 测试 II:客户端向备用地址(但主端口)发送绑定请求。如果测试 II 返回的 XOR-MAPPED-ADDRESS 与测试 I 相同,则 NAT 当前具有端点独立映射。否则,执行测试 III。

  3. 测试 III:客户端向备用地址和备用端口发送绑定请求:
    - 如果 XOR-MAPPED-ADDRESS 与测试 II 匹配,则 NAT 具有地址相关映射(Address-Dependent Mapping)
    - 如果不匹配,则 NAT 具有地址和端口相关映射(Address and Port-Dependent Mapping)

2.确定 NAT 过滤行为

RFC 4787 中对 NAT 过滤行为也分为了三类:

  • Endpoint-Independent Filtering (EIF)
    一旦内部主机发送了一个数据包,任何外部主机都可以通过该映射向 NAT 的外部地址发送响应。

  • Address-Dependent Filtering (ADF)
    仅允许曾接收过数据包的外部 IP 地址发送回数据。

  • Address and Port-Dependent Filtering (APDF)
    更严格,只允许曾接收过数据包的 (外部IP, 外部端口) 回复。

此过程最多需要进行三次测试,且对 NAT 先前状态敏感。

  1. 测试 I:执行 UDP 连接性测试。服务器将在 OTHER-ADDRESS 字段返回备用地址和端口。如果 OTHER-ADDRESS 未返回,无法进行进一步测试。

  2. 测试 II:客户端向服务器的主地址发送绑定请求,并将 CHANGE-REQUEST 属性设置为 change-port 和 change-IP,这将导致服务器从备用 IP 和备用端口发送响应。
    - 如果客户端收到响应,则 NAT 当前具有端点独立过滤(Endpoint-Independent Filtering)
    - 如果未收到响应,则执行测试 III。

  3. 测试 III:客户端向服务器主地址发送绑定请求,并将 CHANGE-REQUEST 设置为 change-port
    - 如果收到响应,则 NAT 具有地址相关过滤(Address-Dependent Filtering)
    - 如果未收到响应,则 NAT 具有地址和端口相关过滤(Address and Port-Dependent Filtering)

在 RFC 5780 中建议可以合并和并行化这些测试,我对上面俩个测试进行了一个简单的合并,如下图:

最后可以简单的看一下这些行为与 RFC 3489 的关系


一位专门做rtc基础框架和平台公司的工程师的说法(他们公司产品主要用在游戏语音,会议等等),说基本上都是用的中继,点对点在实际场景下效果很惨,也是出乎的意料

rtc基本都是中继一个重要原因是跨网udp大概率不通,比如电信到网通,然后就是走中继其实很多时候比直连要快,因为边缘节点可以就近,安排离peer很近的地方,流量进入边缘节点之后就是机房之间的专线通信,低延迟低丢包,然后再就近下发,所以rtc基本都是中继,要不然为啥远程桌面软件都收费,中继的流量费,都rtc了,咋tcp,tcp延迟太高了


stun 服务器如何确定自己在公网上。假如 stun 跟 b 机器同一个子网,之前因为别的原因,a 与 stun 连接上了,现在 a 要跟 b 连接,怎么办?别觉得这问题扯淡,有个 overlay 网络 yggdrasil-go,它一直使用 turn 的模式传送流量,我就在想它能不能每个节点都当一个 stun,可是怎么确定一个节点自身是处于公网呢,在不访问谷歌百度的前提下。得先有一个确认在公网的stun,nat test可以确认自己在不在公网



推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/19620.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


群贤毕至

访客

您的IP地址是:

167.17.67.113