✦工程

NAT 穿透詳解:P2P 遠端桌面如何穿過你的路由器。

你只有一個公用 IP,路由器後面卻有十幾台裝置。你的 iPad 正在使用行動網路,和家隔了三個網路。不知怎麼的,一個遠端桌面 App 在不到一秒內,就從一端打開了到另一端的直接連線,而且通常中間沒有任何中繼。這個魔法其實是這樣運作的:ICE、STUN、TURN、打洞,以及對稱型 NAT 令人尷尬的真相。

為什麼這很重要

想像某個星期二的早晨。你的 Mac mini 在家裡,位於只有單一公用 IPv4 位址的路由器後面。你的 iPad 在火車上,使用電信業者的行動網路,那裡還有自己的多層位址轉換。兩台裝置之間至少隔著兩層 NAT,很可能是三層。預設情況下,兩台機器都無法從外部網際網路被連到。

然而你在 iPad 上打開 Remio,點一下 Mac,一秒後就看到你的桌面了。影像與輸入直接在兩台裝置之間流動,沒有雲端中繼,也沒有中間的代理伺服器重新編碼你的畫面。

讓這件事成為可能的技術有個名字:NAT 穿透,背後是一組定義明確的通訊協定:STUN、TURN 與 ICE。這些正是 WebRTC 用於瀏覽器視訊通話的同一批協定,也是任何現代 P2P 遠端桌面能避免強迫你的畫面影格經過第三方資料中心的原因。本文會逐一說明它們各自的作用、存在的理由,以及它們如何組合起來,在躲在路由器後面的兩台裝置之間找出延遲最低的路徑。

60 秒搞懂 NAT 問題

網際網路原本的設計是讓每台裝置都有自己可公開路由的位址。整個 IPv4 空間大約有 43 億個位址,這在 1981 年綽綽有餘,到 1990 年代後期顯然就不夠了。

變通的辦法是網路位址轉換(NAT)。你的路由器從 ISP 取得一個公用 IPv4 位址。在你家裡,每台裝置從保留範圍(通常是 192.168.x.x 或 10.x.x.x)取得私有位址。當你的筆電送出封包時,路由器會把來源位址改寫成自己的公用 IP、記住這筆對應,然後轉送出去。回覆回來時,路由器查詢這筆對應,再把目的地位址改寫回你的筆電。

這正是連入的連線預設行不通的原因。從外面看,你的筆電沒有位址,只有路由器有。陌生人送到 your-router-public-ip:5060 的封包,會撞上一台沒有對應紀錄的路由器,然後被丟棄。

對 P2P App 來說,這就是整場遊戲。雙方都在路由器後面,而路由器只有在記得自己先送出過東西時才會轉送封包。任何一方都不能直接「打電話」給對方,必須配合各自的路由器,開出一條暫時的通道。

打洞:讓防火牆放你回來

訣竅在這裡。你路由器的 NAT 表是以五元組為索引:來源 IP、來源連接埠、目的地 IP、目的地連接埠,以及通訊協定。當你的裝置送出一個連到 1.2.3.4:5678 的 UDP 封包時,路由器會建立一筆暫時的紀錄,意思是「如果有任何 UDP 封包從 1.2.3.4:5678 回到我公用 IP 的連接埠 X,就把它轉送給這台裝置的連接埠 Y」。

這筆紀錄只會存在一段時間,通常是 30 到 60 秒,除非有東西刷新它,否則就會過期。在這段期間內,任何來自該目的地位址的封包都會被接受。

這就是 P2P App 使用的鑰匙孔。如果雙方都知道對方的公用位址,就可以同時各自對對方送出一個 UDP 封包。雙方的路由器都會開出一筆對外的對應。雙方的第一個封包很可能會被丟棄,因為對方的路由器還沒開出它的對應,但第二個封包就有地方可去了。從那一刻起,兩台路由器都以為自己在轉送一段正常的對外通訊,而兩台裝置其實正在直接對話。

這稱為 UDP 打洞。它有點神奇,文件齊全(RFC 5128),而且對現實中絕大多數消費級 NAT 都有效。剩下的情況,像是對稱型 NAT、CGNAT、公司防火牆,就是 TURN 存在的原因。

打洞不是駭客手法。它正是 NAT 設計時所依循的明確約定:對外的封包會產生對內的許可。P2P App 只是刻意送出那個對外的封包而已。

STUN:「我的公用位址是什麼?」

打洞有一個前提:每個對等端都必須知道自己對外的位址,才能告訴對方要把封包送到哪裡。這個位址從裝置內部是看不到的。你的 iPad 看到的是它的本機 Wi-Fi 位址(192.168.1.42)。路由器改寫封包後,網際網路其他地方看到的卻是完全不同的東西。

STUN,即 NAT 的工作階段穿透工具(Session Traversal Utilities for NAT,RFC 5389),就是解決這個問題的小巧協定。它的流程簡單到有點不好意思:

  1. 對等端送出一個 UDP 封包到公用 STUN 伺服器。(Remio 同時使用 Cloudflare 與 Google 的公用 STUN 伺服器作為備援。)
  2. STUN 伺服器從線路上讀出來源 IP 與連接埠,而依定義,這就是該對等端經 NAT 轉換後的公用位址。
  3. STUN 伺服器把那個位址當作回覆內容送回去:「就我所見,你是 203.0.113.42:48291。」
  4. 對等端現在知道該向對方宣告哪個位址了。

在 ICE 的術語裡,這個對外的位址稱為伺服器反射候選。它的成本幾乎是零:連線建立期間來回一趟,連線建立後則完全沒有頻寬或延遲的額外負擔。STUN 唯一的工作就是讓兩個對等端互相認識;一旦它們開始對話,STUN 伺服器就不再扮演任何角色。

TURN:打洞失敗的時候

打洞對大多數 NAT 有效,但不是全部。失敗的情況是真實存在的,假裝它們不存在的 P2P App,會讓相當一部分使用者根本連不上。

主要的麻煩製造者:

對這些情況,備援方案是 TURN,也就是繞過 NAT 的中繼穿透(Traversal Using Relays around NAT,RFC 5766)。TURN 伺服器是雙方都能連到的中繼站,因為它有一個永遠接受連入流量的公用位址。每個對等端都對 TURN 伺服器發起一條正常的對外 TLS 連線(任何 NAT 都會允許),再由伺服器在兩邊之間轉送位元組。

TURN 是有實際成本的。每個影像封包都必須多經過一個網路躍點。在區域性的 TURN 中繼站上,這會增加約 30 到 80 毫秒的來回延遲。跨區域的情況,例如一端在東京、另一端在聖保羅,中繼站卻在法蘭克福,則可能達到 80 到 200 毫秒。TURN 的營運者還得負擔頻寬:你串流的每一個位元都會經過他們的管線。

這就是設計良好的 App 只有在打洞確實失敗時,才使用 TURN 的原因。這個決定由 ICE 自動處理。

ICE:同時嘗試每一個候選位址

互動式連線建立(Interactive Connectivity Establishment,RFC 8445)是把這一切串在一起的編排。ICE 不會事先挑好策略。它會為每個對等端蒐集所有可能的候選位址,與對方交換完整清單,然後讓雙方的協定堆疊同時探測每一組候選配對,競速找出第一個可行的。

對每個對等端,ICE 通常會蒐集:

兩個對等端透過訊號通道交換這些清單。對 Remio 來說,那是連到 relay.remio.net 的一條小型 WebSocket 連線,攜帶 ICE 候選與 WebRTC 工作階段描述(SDP),而一旦媒體開始流動,它就沒有其他工作了。

兩份清單都到手後,ICE 開始進行連通性檢查。每個對等端依優先順序,沿著每一組候選配對送出 STUN 綁定請求封包。這些優先順序的設計,是為了偏好延遲最低的路徑:

  1. 主機對主機:兩個對等端在同一個區域網路上。這是夢想中的情況:幾百微秒的延遲,不涉及任何路由器。
  2. 主機對伺服器反射,或伺服器反射對伺服器反射:對等端在不同網路上,經由各自的 NAT 打洞連通。實務上,「網際網路上的 P2P」通常指的就是這個。
  3. 任何涉及中繼的路徑:最後手段,只有在較高優先順序的路徑都沒通過連通性檢查時才使用。

第一組雙向都成功的候選配對會被提名為優勝者,媒體開始沿著那條路徑流動。整個過程通常在一秒內就能完成。

ICE 也會持續蒐集候選。如果連線進行到一半出現更好的路徑,例如你的手機離開行動網路、連上 Wi-Fi,ICE 可以在不中斷通話的情況下,重新提名到新的路徑。

為什麼 Remio 極力偏好 P2P

Remio 是遠端桌面 App,不是視訊通話。延遲預算極為嚴苛。要讓連線感覺像是坐在主機前面,整條管線(擷取、編碼、網路、解碼、繪製)都必須非常小:在區域網路上花費約 8 毫秒,其餘則是你的顯示器自己的 60 Hz 更新節奏(每個影格約 16.7 毫秒)。每多一個躍點都是罪過。

在直接的區域網路 P2P 連線上,預算中網路的部分大約是來回 1 到 5 毫秒。沒有中繼;位元組直接從一台裝置送到另一台。搭配 Remio 的管線,區域網路上總共約 8 毫秒的處理時間(內部測量;其餘是你的顯示器自己的 60 Hz 更新節奏),你的輸入會在下一個影格繪製之前就到達。遠端機器感覺起來與本機機器無法區分。

在經 TURN 中繼的連線上,即使是區域性的,網路部分也會跳到 30 到 80 毫秒。使用者感受到的總延遲就變成 40 到 100 毫秒。對大多數工作仍可使用,但快速拖曳或連續快速點擊時你會感覺得到。觸控板不再那麼像是你自己的了。

這個差距,正是我們費這麼大功夫讓連線留在 P2P 的原因。Remio 的 WebRTC 堆疊同時蒐集 IPv4 與 IPv6 候選、並行連到多個 STUN 伺服器,並在 ICE 的候選配對選擇中積極偏好直連路徑。在內部,我們甚至會用量測到的連線 RTT 來分類網路:低於 15 毫秒就知道是區域網路,編碼器會以高位元率開始,並可使用多得多的頻寬。任何更慢的都視為廣域網路,並以較保守的方式調校。

還有一點(這是競爭對手常常悄悄略過的部分):無論走哪條路徑,連線都是端對端加密的。你的畫面絕不會經過我們的伺服器,即使是 TURN 中繼也只會看到密文:金鑰是在握手期間、任何像素移動之前,由兩個對等端直接協商的。不論位元組是走 P2P 還是經過 TURN,Remio 的訊號伺服器與 TURN 營運者都讀不到它們。P2P 只是代表資料路徑上完全沒有第三方。

當中繼無可避免時(這沒關係)

有時候網路之神就是說不。兩端都是對稱型 NAT、嚴格 ISP 的行動網路上的雙層 CGNAT、只允許連到已知雲端供應商的對外 TLS 的公司防火牆,這些都是真實而常見的配置。在這些情況下,連線就是得經過中繼,否則根本無法成立。

Remio 的 TURN 後端是 Cloudflare Calls,它為我們提供了貼近大多數使用者的全球中繼網路。當 ICE 選擇中繼路徑時,體驗會從「感覺像在本機」降到「感覺像 Splashtop」:依然很好用,但你分辨得出來。區域性中繼增加的延遲落在 30 到 80 毫秒;跨區域可能達到 200 毫秒。

重點是:資料依然是端對端加密的。Cloudflare 看到的是往一個方向的加密 UDP 封包,與往另一個方向的加密 UDP 封包。它可以為了計費而計算位元組數,但看不到你的畫面、你的按鍵,或你連線內容的任何部分。Remio 這一側也沒有任何解密點,因為管線中根本沒有 Remio 的雲端:我們透過 Cloudflare 營運 TURN 服務,從不碰觸酬載。

這就是我們的安全性白皮書更詳細描述的架構。簡而言之:無論是 P2P 還是中繼,威脅模型都是一樣的。

IPv6 這條退路

IPv6 有 340 澗個位址(3.4 × 1038),足以讓地球上每一粒沙都有自己的公用 IP,還綽綽有餘。在純 IPv6 的世界裡,NAT 大致上是不必要的。兩台支援 IPv6 的裝置可以直接把封包送到對方的位址,唯一的障礙是兩端的主機防火牆。

如果你家裡和行動網路業者都有 IPv6,你可能注意到,當兩端都是 IPv6 時,有些 App 連線更快,這是因為整套「蒐集候選、探測配對」的過程,障礙變少了。不需要探索 NAT 轉換、不需要往返 STUN,只要直接的位址就行。

但問題是:到了 2026 年,全球的推行仍未完成。許多家用路由器對 IPv6 支援不佳,或根本不支援。許多公司網路預設封鎖連入的 IPv6。有些業者在無線電端提供 IPv6,其他地方卻橋接回 IPv4。純 IPv6 對 IPv6 的路徑確實存在,卻不能作為唯一的機制來依賴。

所以 Remio 就像每個嚴肅的 P2P 堆疊一樣,同時蒐集 IPv4 與 IPv6 候選,讓 ICE 去競速。如果存在可用的直接 IPv6 路徑,它通常會在延遲上勝出;如果沒有,就由搭配打洞的 IPv4 接手;兩者都失敗,就走中繼。使用者完全看不到這些,連線就這樣建立起來了。

如何知道你的連線走的是哪條路徑

好奇你的連線最後走了哪條路徑嗎?Remio 的連線指示器會以淺白的語言顯示類型:P2P 顯示「直連」,TURN 顯示「中繼」。開發者統計面板則呈現完整的 WebRTC 狀態,包括被提名的配對之候選類型(host、srflx、relay)與量測到的 RTT。

幾個快速的解讀:

如果你就算在家也總是退回中繼,常見的嫌疑對象是 ISP 數據機採用對稱型 NAT、你家連線的 IPv4 CGNAT(在光纖轉售商上比你想像的更常見),或是過度熱心的防火牆封鎖了連入的 UDP。我們的降低遠端桌面延遲指南會帶你檢查常見的罪魁禍首;如果兩台裝置都在你的網路上,區域網路直連頁面是最快的路徑。

實際的效能數據

綜合起來,以下是我們在正式環境中,針對 Remio 連線可能走的不同路徑所量測到的延遲數字:

這些與 Remio 效能基準中的數字相符,也解釋了我們為什麼把區域網路與廣域網路的門檻設在 15 毫秒 RTT:它能乾淨地把直連路徑與任何中繼(最少 30 毫秒)或行動網路路徑(最少 40 毫秒)區分開,誤判非常少。

NAT 穿透是那種單看每個協定都很簡單、組合起來卻很棘手的主題。大多數使用者永遠不需要知道 ICE、STUN 與 TURN 的存在,他們只會體驗到一個能從任何地方快速連到任何地方的 App。當你注意不到這些協定時,它們就是在做好自己的工作。而當你注意到了,例如連線多花了一點時間,或是「直連」變成了「中繼」,你現在就有了這套心智模型。

想進一步了解 Remio 的原生管線,以及如何把 1 到 5 毫秒的網路延遲變成約 8 毫秒的處理時間(其餘是你的顯示器自己的 60 Hz 更新節奏),請見為什麼原生很重要。關於中繼路徑的威脅模型,請見安全性白皮書。或者直接瀏覽功能並下載 Remio,親身感受它的運作。

✦常見疑問

常見問題

什麼是 NAT 穿透?
NAT 穿透是點對點 App 用來在兩台各自位於家用或辦公室路由器後面的裝置之間,建立直接連線的一組技術。由於路由器會把許多私有 IP 位址轉換成一個公用 IP(網路位址轉換,即 NAT),連入的連線預設會被封鎖。NAT 穿透(主要是 ICE、STUN 與 TURN)會探索每台裝置對外的位址、穿過兩台路由器開出一條暫時的通道,只有在直接打洞失敗時,才退回到中繼伺服器。
STUN 是如何運作的?
STUN(NAT 的工作階段穿透工具)是一個小型的請求與回應協定。用戶端送出一個 UDP 封包到公用 STUN 伺服器,伺服器則回覆它在線路上實際看到的來源 IP 與連接埠,也就是公用網際網路所看到的、該用戶端經 NAT 轉換後的位址。用戶端接著透過訊號通道向對等端宣告該位址,讓對等端知道該把封包送到哪裡。STUN 本身在連線建立期間只增加約一趟來回的延遲,之後則完全沒有額外負擔。
STUN 與 TURN 有什麼不同?
STUN 只負責告訴每個對等端它自己的公用位址,讓它們能嘗試直接連線。TURN 則是在無法建立直接連線時,真正透過雲端的伺服器中繼媒體。STUN 幾乎不增加延遲或頻寬成本;TURN 多了一個躍點,區域性中繼大約增加 30 到 80 毫秒的延遲,並消耗伺服器端的頻寬。設計良好的 P2P App 會先用 STUN,只在必要時才退回 TURN。
為什麼我的遠端桌面會退回中繼?
當一端或兩端位於對稱型 NAT、電信業者等級 NAT(在行動網路上很常見),或是封鎖必要 UDP 流量的嚴格公司防火牆後面時,直接的點對點打洞就會失敗。這時 App 會退回 TURN 中繼,讓連線仍然可以運作。連線依然是端對端加密的,中繼只會看到不透明的加密資料,但區域性中繼會增加 30 到 80 毫秒的延遲,跨區域則最多 200 毫秒。
WebRTC 中的 ICE 是什麼?
ICE(互動式連線建立)是整合所有位址探索技術並同時嘗試它們的框架。每個對等端蒐集一份候選位址清單:區域網路的(主機)、經由 STUN 取得的公用位址(伺服器反射),以及 TURN 中繼的,然後與對方交換這份清單。兩邊的協定堆疊同時沿著每一組候選配對送出探測封包,第一組成功的配對勝出。優先順序較高的候選(主機,其次是伺服器反射,再其次是中繼)會被優先採用,所以在可行時會選到延遲最低的路徑。
IPv6 能免除 NAT 穿透的需求嗎?
大致上可以:IPv6 讓每台裝置都有可路由的公用位址,所以兩個支援 IPv6 的對等端可以不經轉換直接連線。但在 2026 年,仍有大量家用與行動網路只有 IPv4 或是雙協定堆疊,許多防火牆也預設封鎖連入的 IPv6。因此 NAT 穿透仍是必要的備援,大多數正式環境的 App 會同時蒐集 IPv4 與 IPv6 候選,讓 ICE 挑選連線最快的路徑。
Remio App 圖示

感受直連的路徑。

Remio 讓每個候選位址競速,找出通往你機器延遲最低的路線:不需要連接埠轉發、不需要 VPN,P2P 或中繼都是端對端加密。

免費使用不需帳號30 秒完成配對