為什麼乙太網路的把戲在空中行不通
回到有線區域網路那個階梯,你見過一條共享單一條纜線的乾淨規則:CSMA/CD,也就是帶碰撞偵測的載波感測多重存取。一個站台在開口前先聆聽,而且——精巧之處在於——它在開口時持續聆聽。在導線上,你自己的訊號與一個相撞的訊號加在一起,會形成一個看起來不像乾淨資料的電壓,於是傳送端在幾微秒內就察覺撞車、停下、退避。在傳送途中偵測,正是有線乙太網路又快又公平的原因。
在空中,這個把戲因為一個你在第一篇指南看過、殘酷而物理的原因而崩潰:一台無線電從遠處收到的訊號,比它自己天線正在發射的訊號弱得驚人——輕易就弱上一百萬到十億倍。當一台 Wi-Fi 無線電正在傳送時,它自己發出的巨響會徹底震聾它的接收端。它就是聽不見從房間另一頭飄來的微弱相撞訊號,就像火警警報器旁邊的耳朵聽不見一句耳語。所以一台無線電在傳送時無法偵測碰撞。沒得商量。
CSMA/CA:聆聽、隨機等一拍、再開口
既然無線電無法在當下抓到碰撞,Wi-Fi 退而求其次:它努力讓碰撞根本不要發生。這套機制叫 CSMA/CA,其中 CA 代表碰撞避免(collision avoidance)。載波感測的那一半跟導線上一樣——先聆聽,如果已經有人在說話就保持安靜。新的那一半,是當通道變成空閒時你要做什麼。
這裡是它的核心。在導線上,纜線一安靜下來,每個人就同時撲上去——而偵測會清理隨之而來的撞車。在空中沒有清理可言,所以 Wi-Fi 禁止這種撲上去。當通道變成空閒時,每個等待中的站台不會立刻傳送;它會挑一個隨機數目的微小時槽往下倒數,只有在自己私下的倒數歸零時才送出。因為這些倒數是隨機的,兩個站台幾乎不會在同一個時槽歸零,於是它們輪流而非相撞。這是一個有禮貌的房間,在一段停頓之後,每個人默默擲骰子,點數最低的先開口。
- 感測通道。如果它已空閒一段短而固定的間隔,你就可以繼續;如果它忙碌,就等到它安靜下來。
- 挑一個隨機退避:從一個時槽視窗(比方說 0 到 15)中選一個數,只在通道保持空閒時往下數,每當別人在說話就把計數器凍結。
- 當你的計數器歸零時,傳送框幀。
- 等待接收端的一個確認。因為空中是會丟失的,每一個單點傳送的框幀都必須被明確確認——沉默被視為失敗。
- 沒收到 ACK?就假設發生了碰撞或衰落,把你的隨機退避視窗加倍,再試一次。反覆失敗就退避得更猛,這跟 TCP 那位謹慎駕駛的剎車本能如出一轍。
留意那個確認。在有線乙太網路上沒有鏈結層的 ACK——一個框幀要嘛相撞(而傳送端看到了),要嘛抵達。在 Wi-Fi 上,傳送端對發生了什麼一無所知,所以接收端必須出聲:一個缺席的 ACK,是傳送端得知它的框幀遺失了的唯一途徑,無論是因為碰撞,還是因為你上次研究過的衰落與干擾。這就是為什麼 Wi-Fi 會在鏈結層重試,早在 TCP 會注意到之前就藏起許多遺失。
隱藏終端,與 RTS/CTS 交握
載波感測在空中有一個導線從未有過的深層缺陷。想像中央有一個存取點,左邊是筆電 A,右邊是筆電 C。A 與 C 都在存取點的範圍內,但一面牆加上距離,意味著 A 與 C 彼此完全聽不見。這就是隱藏終端問題。當 A 在傳送前聆聽時,通道聽起來是空閒的——因為 C 對 A 而言是隱藏的——於是 A 傳送。C 同樣聽不見 A,也聽到空閒,於是 C 也傳送。它們的兩個訊號在中央的存取點相撞,然而兩個傳送端都無從得知。
在傳送端聆聽問錯了問題。真正要緊的是通道在接收端是否淨空,而只有接收端能回答這件事。所以 802.11 提供了一個選用的交握,RTS/CTS,讓接收端能清出場子。在送出一個大框幀之前,A 先對存取點低聲說一句小小的「請求傳送」(RTS)。存取點以一句「可以傳送」(CTS)回應——而關鍵在於,存取點能觸及的每個人都聽得見那句 CTS,包括隱藏的 C。那句 CTS 帶著一個持續時間,任何聽見它的站台都會剛好安靜那麼久。
A -----RTS----> [AP] <----(C is hidden from A) A <----CTS----- [AP] -----CTS----> C (C hears CTS, stays quiet) A -----DATA---> [AP] A <----ACK----- [AP] RTS/CTS are tiny: a collision of two short RTS frames is cheap; a collision of two big DATA frames is what we paid to avoid.
重點在於經濟划算。RTS 與 CTS 框幀都很小,所以即使兩個隱藏傳送端的 RTS 框幀相撞,幾乎沒有浪費任何空中時間——它們只要退避、重試即可。昂貴的東西,也就是一個完整的資料框幀,要等到空中被預約好了才送出。話雖如此,這個交握在每次交換都會增加額外負擔,所以真實的 Wi-Fi 只為超過某個大小門檻的框幀開啟 RTS/CTS,那種情況下保護才值得這個成本。這是一個誠實的取捨,而非免費的勝利:你總是花一點空中時間,去省下當隱藏終端否則會衝突時的大量空中時間。
802.11 架構:存取點、SSID、關聯
現在從空中時間的規則拉遠,看看一個 Wi-Fi 網路的形狀。常見的配置是基礎建設模式:每個裝置都與一個中央存取點(AP)對話,而 AP 在無線世界與它背後的有線網路之間轉送框幀。AP 扮演一個你從區域網路那個階梯已經認識的角色——很像一台會學習誰在哪裡的交換器——只不過它的連接埠是無線電通道,而它的客戶端不斷在移動。在這裡裝置不會筆電對筆電直接對話;它們全都經過 AP,這正是為什麼隱藏終端的解藥要讓 AP 送出那句 CTS。
你的手機怎麼找到一個可加入的網路?每個 AP 會週期性地廣播一個小小的信標,宣告它的 SSID——也就是像「CafeWiFi」這樣人類看得懂的網路名稱。你的手機聽見這些信標,把清單顯示給你。挑一個就開始關聯:你的裝置與 AP 交換幾個管理框幀,議定參數,並(若有加密)用密碼進行認證,而 AP 把你的裝置記錄為它的客戶端之一。只有在關聯之後,你才可以送出一般的資料框幀。把它想成在進入大樓前先到櫃台辦理報到。
還有第二種、更精簡的形狀值得認識。在隨意模式裡根本沒有存取點;裝置組成一個對等群組,彼此直接對話。它對於快速建立筆電對筆電的連結很方便,但少了中央協調者,隱藏終端問題咬得更兇,網路也無法擴展,這就是為什麼幾乎每個家庭、辦公室與咖啡店都跑基礎建設模式。一位近親住在極短的距離裡:藍牙,它用自己的主從結構與快速跳頻,來共享同樣擁擠的 2.4 GHz 頻段,供鍵盤、耳機與手錶使用——為不同的工作準備的不同規則手冊。
為什麼這件事一路向上影響到 TCP
把這一切想成低階的無線電水管工程很有誘惑力,但它會向上滲漏。記得在傳輸層那個階梯,傳統 TCP 會把任何封包遺失解讀為壅塞的徵兆,並猛踩剎車——那位謹慎的駕駛踩下踏板。然而在 Wi-Fi 上,一個遺失的框幀更常是衰落、一陣干擾,或空中的一次碰撞,而非某個路由器佇列滿了的徵兆。如果那些遺失傳到 TCP,它就會在一條其實並不壅塞的連結上毫無必要地慢下來。
你稍早看到的鏈結層 ACK 與重試,部分正是為了藏起這件事而存在。透過在放棄前於空中重送一個丟掉的框幀幾次,Wi-Fi 把許多快速的無線電遺失,變成一點額外的延遲,於是 TCP 根本看不到它們是遺失。這是一種刻意的掩蓋,多半有幫助——但這也是為什麼微弱的 Wi-Fi 訊號感覺像是卡頓而非斷線:在引擎蓋底下,連結正悄悄重送,用延遲去掩蓋第一篇指南裡那些位元錯誤的風暴。
但這種掩蓋從來不完美,而那道裂縫正是通往本階梯其餘部分的橋樑。當你走出範圍、當干擾飆升,或當你在存取點之間漫遊時,遺失與卡頓確實會傳到 TCP,而無線現實與 TCP 壅塞假設之間的這種不匹配,正是無線 TCP 效能的核心——也就是第五篇指南的主題。不過首先,第三與第四篇指南會把免授權的 Wi-Fi 頻段拋在身後,踏進蜂巢式網路那個有授權的世界,在那裡是一個基地台,而非一個有禮貌、擲骰子的房間,來排定誰在何時開口。