網路就是相連、能對話的東西
撥開術語,一個網路簡單到幾乎令人不好意思:兩台或更多裝置由某條連線接在一起,並同意彼此交換資料。你的筆電與印表機用一條線相連,這是網路;你的手機與一台 Wi-Fi 路由器相連,也是網路。讓它成為網路的,不是那條線或那道電波,而是雙方事先就「如何輪流發話」與「訊息該長什麼樣子」達成了共識。我們給這個概念一個正式名稱:電腦網路,也就是一組互相連接、能夠共享資料的裝置。
把每張網路拆成兩個世界會很有幫助。在邊緣的,是你真正在乎的裝置——筆電、手機、伺服器、智慧門鈴。我們把每一台這樣的裝置稱為端系統(或主機):它執行你的程式,是資料的來源或最終目的地。而夾在中間、唯一工作就是把資料一站站接力傳下去的那些盒子,則組成了網路核心。邊緣是對話開始與結束之處;核心則是中間那張道路網。
網際網路:網路之網路
接下來這一步改變了一切。網際網路(大寫的 Internet)不是一張巨大的網路,而是數以萬計各自獨立營運的網路——你家的網路、你的大學、Google 的網路、某家電信業者的網路——彼此同意互相連接而成。沒有人擁有它。它能運作,是因為所有這些網路都講同一種共通語言。這種語言就是 TCP/IP 這一家族的通訊協定,而位居正中央、把一切黏起來的萬用膠水,是網際網路協定,也就是 IP。任何會講 IP 的網路都能加入,這正是網際網路能從一九六九年的四台電腦長成今天數十億台的原因。
上面那段裡真正扛重活的詞是通訊協定。一個通訊協定是一份有三個部分的約定:訊息的格式(哪些位元組代表什麼意思)、訊息可被送出的順序(先打招呼,才能發問),以及當一則訊息抵達、或某個計時器到時所要採取的動作。人類也使用協定——一通電話就是「喂?——嗨,是我——……」。當兩台機器遵循的是完全相同的協定時,雙方都不必理解對方的硬體、作業系統或語言;它們只需照著同一套腳本走。
這些大家同意的腳本是從哪裡來的?大多來自一種叫做 RFC(Request for Comments,徵求意見書)的公開文件。一份 RFC 就是一份公開發表的規格書——IP、TCP、HTTP、DNS 全都活在一份份編了號、任何人都能免費閱讀的 RFC 裡。這種開放性絕非無關緊要的小註腳;它正是「一家公司造的手機,能和半個地球外、另一家公司造的伺服器對話」的根本原因。
為什麼我們把資料切成封包
那麼,資料究竟是如何穿過核心的?你也許會想像網路在發送端與接收端之間,為整段對話拉起一條私人專線。那叫做電路交換,是老式電話系統的運作方式:先預約一條路徑,整通電話期間都佔著它,連沉默時也不放。這保證了穩定的速率,卻在沒人說話時白白浪費了那條連線——而電腦之間的對話,多半是被突如其來的爆量打斷的沉默。
網際網路做了相反的選擇:分封交換。我們把每則訊息切成一個個小而自足的區塊,稱為封包,在每個封包上蓋上目的地位址,然後讓網路一跳接一跳地各自轉送它們,與其他所有人的封包共用同樣的連線。把封包想成一張明信片:它帶著一個位址和訊息的一小段,郵政系統在每個分揀中心讀取位址,再把它往下一站送。沒有任何路徑被事先預約,所以當你一停下來,你那份連線立刻就空出來給別人用了。
讓這一切運作起來的,有一個小而關鍵的機制,叫做儲存後轉送。核心裡的交換器必須先收完一整個封包並加以檢查,才能把它往下送——它無法去轉送一個只收到一半的封包。所以在每一跳,封包都會被完整地儲存下來,然後才轉送出去。這就是為什麼封包的旅程是一段段完整跳躍的接力,而不是一路連續滑行;這裡也是延遲悄悄開始累積的第一個地方(下一篇指南會精確衡量到底累積了多少)。
那個最重要的觀念:分層
想像一下,如果你寫網頁瀏覽器的程式時,得同時親手管理銅線上的電壓、Wi-Fi 的無線電時序、橫跨四十張網路的路徑,以及網頁本身的規則,全部糾纏成一團——那會是不可能的任務。從這場惡夢中逃脫的辦法,就是網路領域裡最強大的一個觀念:分層。我們把整個問題切成一疊層,每一層只做一件事,向上面那層提供一個乾淨的服務,同時也只向下面那層索取一個乾淨的服務。
讓各層得以堆疊起來的機制是封裝:每一層在把上層交下來的資料往下傳之前,會用自己的標頭(有時還有一段尾端)把它包起來,就像一層層套疊的信封。網頁那層的訊息被裝進一個傳輸層的信封(例如加上一個連接埠號碼,好讓接收端知道該交給哪個程式),這個信封又被裝進一個 IP 信封(加上目的地位址),再被裝進一個給下一跳用的連結層信封。到了另一端,信封以相反的順序被一個個打開。每一層只讀自己那個信封、忽略裡頭的內容——這正是讓你能把 Wi-Fi 換成光纖、卻完全不必動到瀏覽器的緣由。
Sending (top -> bottom), each layer adds its envelope:
Application: [ GET /index.html ] <- your data
Transport: [ TCP hdr | GET /index.html ] <- adds port, seq#
Network: [ IP hdr | TCP hdr | GET /index.html ] <- adds dst address
Link: [ Eth hdr | IP hdr | TCP hdr | data | FCS ] <- adds MAC, checksum
v put on the wire / air v
Receiving: peel the envelopes back off, bottom -> top.兩張分層地圖:OSI 與 TCP/IP
有兩張著名的分層地圖會陪你走完這整道階梯。OSI 模型是一套整齊的七層參考模型(實體層、資料連結層、網路層、傳輸層、會議層、表現層、應用層),由委員會設計,作為教學與設計用的框架。TCP/IP 模型則是真實網際網路實際運行、比較精簡的四層堆疊(連結層、網際網路層、傳輸層、應用層)。要誠實看待兩者的關係:OSI 是大家都從中學習的課堂示意圖,但真正在運轉的網際網路是 TCP/IP。人們會隨口借用 OSI 的層號——「第二層交換器」、「第七層負載平衡器」——即便他們的設備跑的其實是 TCP/IP。
那為什麼還要學那套七層的呢?因為它的詞彙無所不在,而且它多出來的那幾層(會議層、表現層)所命名的,是真實存在的考量——即使 TCP/IP 把它們折進了應用層裡。把 OSI 當成參考用的共通語言,把 TCP/IP 當成實際的實作。本級的第五篇指南會把兩者並排、一格一格對照;現在你只要把那個形狀記在腦海裡:一疊層,資料外送時往下穿過一層層信封,內收時再往上一層層脫出信封。
- 先挑出你此刻真正在乎的那一層——而且幾乎總是只有一層。在載入一個網頁嗎?那就是應用層。
- 問問下面那層承諾給它什麼乾淨的服務。網頁只是向傳輸層要一條「通往那台主機與連接埠的可靠位元組管線」,然後信任它。
- 讓底下每一層各自守住自己的承諾,而不必你盯著看:傳輸層處理遺失與順序,網路層處理路徑,連結層處理單一一跳。
- 當有東西壞掉時,你現在知道該去檢查哪一層了——而這,正是分層在日常裡真正的回報。