你只有一個公用 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),就是解決這個問題的小巧協定。它的流程簡單到有點不好意思:
- 對等端送出一個 UDP 封包到公用 STUN 伺服器。(Remio 同時使用 Cloudflare 與 Google 的公用 STUN 伺服器作為備援。)
- STUN 伺服器從線路上讀出來源 IP 與連接埠,而依定義,這就是該對等端經 NAT 轉換後的公用位址。
- STUN 伺服器把那個位址當作回覆內容送回去:「就我所見,你是
203.0.113.42:48291。」 - 對等端現在知道該向對方宣告哪個位址了。
在 ICE 的術語裡,這個對外的位址稱為伺服器反射候選。它的成本幾乎是零:連線建立期間來回一趟,連線建立後則完全沒有頻寬或延遲的額外負擔。STUN 唯一的工作就是讓兩個對等端互相認識;一旦它們開始對話,STUN 伺服器就不再扮演任何角色。
TURN:打洞失敗的時候
打洞對大多數 NAT 有效,但不是全部。失敗的情況是真實存在的,假裝它們不存在的 P2P App,會讓相當一部分使用者根本連不上。
主要的麻煩製造者:
- 對稱型 NAT。這種 NAT 會為每個不同的目的地分配不同的公用連接埠。STUN 告訴你的對等端你在連接埠 48291(因為 STUN 伺服器看到的是這個連接埠),但當你把封包送到對等端的位址時,你的路由器卻選了另一個連接埠,比方說 48317。對等端的路由器因為封包來自意料之外的連接埠,而拒絕了它。打洞就此失敗。
- 電信業者等級 NAT(CGNAT)。行動網路與許多 ISP 網路會在業者層級再疊一層 NAT。你可能在不知情的情況下,位於兩層 NAT 之後,而且兩層都必須配合。CGNAT 通常是對稱型,而你沒有任何管理權限。
- 限制嚴格的公司防火牆。部分企業網路會封鎖所有對外的 UDP,或只允許連到特定目的地。打洞需要一條 UDP 通道,沒有的話就毫無機會。
對這些情況,備援方案是 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 通常會蒐集:
- 主機候選:每個網路介面上的每個本機 IP 位址(乙太網路、Wi-Fi、虛擬介面,IPv4 與 IPv6)。
- 伺服器反射候選:從 STUN 伺服器得知的公用位址。
- 中繼候選:在 TURN 伺服器上配置的位址。
兩個對等端透過訊號通道交換這些清單。對 Remio 來說,那是連到 relay.remio.net 的一條小型 WebSocket 連線,攜帶 ICE 候選與 WebRTC 工作階段描述(SDP),而一旦媒體開始流動,它就沒有其他工作了。
兩份清單都到手後,ICE 開始進行連通性檢查。每個對等端依優先順序,沿著每一組候選配對送出 STUN 綁定請求封包。這些優先順序的設計,是為了偏好延遲最低的路徑:
- 主機對主機:兩個對等端在同一個區域網路上。這是夢想中的情況:幾百微秒的延遲,不涉及任何路由器。
- 主機對伺服器反射,或伺服器反射對伺服器反射:對等端在不同網路上,經由各自的 NAT 打洞連通。實務上,「網際網路上的 P2P」通常指的就是這個。
- 任何涉及中繼的路徑:最後手段,只有在較高優先順序的路徑都沒通過連通性檢查時才使用。
第一組雙向都成功的候選配對會被提名為優勝者,媒體開始沿著那條路徑流動。整個過程通常在一秒內就能完成。
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。
幾個快速的解讀:
- RTT 低於 5 毫秒,直連:你和主機在同一個區域網路上。最佳情況。可達成約 8 毫秒的處理時間(其餘是你的顯示器自己的 60 Hz 更新節奏)。
- RTT 5 到 15 毫秒,直連:在同一個 Wi-Fi 網路上,但多經過一個無線基地台或 Mesh 躍點。依然很出色。
- RTT 15 到 80 毫秒,直連:你和主機位於不同網路,打洞成功。網際網路 P2P 運作中。
- RTT 30 到 80 毫秒,中繼(區域性):對稱型 NAT 或電信業者等級 NAT 擊敗了打洞。附近的 Cloudflare TURN 接手了。
- RTT 80 到 200 毫秒,中繼:TURN 跨越較長的地理距離,或是你和主機位於相差甚遠的區域。
如果你就算在家也總是退回中繼,常見的嫌疑對象是 ISP 數據機採用對稱型 NAT、你家連線的 IPv4 CGNAT(在光纖轉售商上比你想像的更常見),或是過度熱心的防火牆封鎖了連入的 UDP。我們的降低遠端桌面延遲指南會帶你檢查常見的罪魁禍首;如果兩台裝置都在你的網路上,區域網路直連頁面是最快的路徑。
實際的效能數據
綜合起來,以下是我們在正式環境中,針對 Remio 連線可能走的不同路徑所量測到的延遲數字:
- 區域網路直連 P2P:網路 RTT 1 到 5 毫秒。端對端(輸入事件到像素更新):約 8 毫秒的處理時間(其餘是你的顯示器自己的 60 Hz 更新節奏),其餘管線配合良好。
- 同一個 Wi-Fi 網路但多幾個躍點:網路 RTT 5 到 10 毫秒。
- TURN 中繼,區域性:網路 RTT 30 到 80 毫秒。
- TURN 中繼,跨區域:網路 RTT 80 到 200 毫秒。
- 4G/5G 行動網路,打洞的 P2P:網路 RTT 40 到 100 毫秒。
這些與 Remio 效能基準中的數字相符,也解釋了我們為什麼把區域網路與廣域網路的門檻設在 15 毫秒 RTT:它能乾淨地把直連路徑與任何中繼(最少 30 毫秒)或行動網路路徑(最少 40 毫秒)區分開,誤判非常少。
NAT 穿透是那種單看每個協定都很簡單、組合起來卻很棘手的主題。大多數使用者永遠不需要知道 ICE、STUN 與 TURN 的存在,他們只會體驗到一個能從任何地方快速連到任何地方的 App。當你注意不到這些協定時,它們就是在做好自己的工作。而當你注意到了,例如連線多花了一點時間,或是「直連」變成了「中繼」,你現在就有了這套心智模型。
想進一步了解 Remio 的原生管線,以及如何把 1 到 5 毫秒的網路延遲變成約 8 毫秒的處理時間(其餘是你的顯示器自己的 60 Hz 更新節奏),請見為什麼原生很重要。關於中繼路徑的威脅模型,請見安全性白皮書。或者直接瀏覽功能並下載 Remio,親身感受它的運作。