淺談傳輸層協定:TCP 及 UDP
前面提到 TCP/IP 模型,TCP 和 IP 兩個協定可說是現今網路架構的最重要的協定之二。
TCP 在 OSI 及 TCP/IP 模型中都是屬於傳輸層的協定,而在傳輸層其實也有另一個廣泛被使用的協定,叫做 UDP(User Datagram Protocol,使用者資料報協定),做的事情略有不同。
聊完了 IP 之後,我們接著來看看這兩大傳輸層協定,先從 TCP 開始。
TCP 在做什麼?
回顧一下 TCP 的全稱:Transmission Control Protocol 傳輸控制協議,這個協定故名思義就是在控制傳輸的大小事。
在 IP,網路層這個階段,基本上只管我從哪來、我往哪去?但是封包不見了、裡面的資料壞掉了,IP 一概不管。這時候 TCP 就起到至關重要的作用了!確保連線的可靠性就是其主要任務,它有一系列的手段去確保資料能夠送到對方手中,
IP 不可靠的部分,就留給 TCP 做了,包括確保資料抵達目的地、資料的順序一致(這是由於一份資料可能會被切成數份傳送)、資料沒有損壞、流量的控制等等。
TCP 連線及連接埠
TCP 會在兩個端點間建立一個連線(稱做 Socket Connection)來確保雙方的溝通順暢,就像是一條電話專線一樣。在這個連線之中,會在來源及目的各指定一個連接埠(Port),作為確認這個連線的編號。
由於 TCP 是基於 IP 的上面一層,TCP 的連線都會在同一個 IP Address 下,可以理解為都與同一台設備進行連線。但兩個設備間的連線可能不只一個,就會需要編號來分開不同的連線。用 Port(港口,計算機領域譯成連接埠)來命名編號,就像是在同一個地區(同一個 IP Address)有不同的港口。
例如在 IP 位置為 87.65.43.21
的伺服器中開了一個 Port 80
,這是伺服器專門為 HTTP 開的 Port,伺服器會一直等待新的封包進來,看看有沒有 TCP 協定要傳的內容,Port 是指定 80
的,而這個等待連線產生的行為就被稱為監聽(Listen)。
IP 位置為 12.34.56.78
也是一台裝置,可能自己也有啟動一些服務,也有架設網站,因此也會監聽自己的 Port 80
。但當這台裝置也想連到另一台裝置使用對方 HTTP 服務的時候,它會找一個目前沒有在用的 Port,如 12345
(總之不能是現在有開的 22
, 80
Port),當作來源,和對方的 Port 80
建立合法的 TCP 連線。
Port 的數字大小必須介於 1-65535 間,因為 TCP 要存放來源及目的 Port 的長度只有 16 bits 而已。一些常用的服務都會被保留起來,例如 HTTP 這個應用層的服務通常都是 80、SSH 都是 22 等等,這是約定俗成的定義,也就是說如果你想,你也可以佔用這些 Port 去啟用你自己的網路服務。
TCP 如何建立連線?三向交握
要建立可靠的連線,TCP 提出的辦法是我知道你知道我知道,很饒舌吧!這個建立連線的方法稱做「三向交握」(Three-way handshake),原理其實很簡單,就是先丟個訊息和對方確認,對方回答,我們再做最後回應。
三次傳遞訊息分別用來達成及確認一些事情
- 確認建立連線,確認我方到對方的網路是通的
- 回應是否建立連線(對的,有可能被對方拒絕),以及告訴我方,網路從對方來的這條路徑是通的
- 最後讓對方知道,我方到對方的路徑是通的
你可能會想,第 3 次的訊息有必要嗎?不是在第 1 次就讓對方知道我們的訊息傳的到了?
這幾次交握的訊息中還藏著「序列號碼」(seq, sequence number)及「確認號」(ack, acknowledgement number)。由於一筆資料可能會很大,並且 IP 這個協定有限制每個封包的最大大小,因此 TCP 用序列號碼來記錄被分割後的每一份小資料。
有了序列號碼之後,在交握同時會附帶這個訊息,對方收到後的回覆則會包含「確認號」,也就是對方期待收到的下個序列號碼為何,藉此來確保封包是連續的。
確認過眼神,便可以開始傳輸資料了,接下來,我們繼續看看 TCP 如何管理資料傳輸。
TCP 怎麼檢查你的資料有沒有損壞?
我們先來看看資料「損壞」這件事情。現實世界中的如果送包裹,過程中沒有壓到、摔到,完好無缺的抵達目的地,我們就說這個包裹沒有損壞。但在網路世界不太一樣,資料被轉換成電流或是無線電波傳送,如果突然打了個雷之類的讓介質中有什麼干擾,傳播中的資料肯定就此毀壞。
還好,我們傳送的資訊都數位化了,如果這次傳送的資訊壞了會沒收到,大不了再傳一次,成本反正很低,這可是真實世界的包裹難以達成的。也就是說,如果資料「損壞」了,在網路世界只要重新傳送就好,重點就在怎麼檢查資料在傳輸過程中還完不完好。
由於資料會被拆成數個封包傳送,TCP 找出錯誤的方式便有以下幾種方式:檢驗資訊是否有誤、封包掉了就重送、看看序號是否連續。
序號連續這件事在聊 TCP 三向交握的時候提了一些,所以我們接著來看看檢驗資料錯誤和重送機制吧。
Checksum 檢驗和
要檢驗資訊是否有誤,TCP 的解法是 Checksum,就是檢驗某些數值的加總是否一致,這在計算機領域也是常用來做錯誤偵測的一種方法。
由於傳輸的資料是數位的,最基本的模樣由 0 和 1 所組成,我們 TCP 就把 Port、序號、要傳的資料等等這些數字化的資訊加總在一起,所以稱做檢驗「和」(Sum)。這個「和」也會被放在這筆資料內一起送出去,接收的時候把傳送的資料和這個「和」驗證一下。
舉個例子來說,我們傳的資料是 1 3 5 7 9 1
,Checksum 就是把這些數字加起來,得到 26
。但是當然不會把加起來的數字直接傳過去,因為要傳的資料可能很長,得到的 Checksum 就會很大,TCP 的定義不容許太大的 Checksum 存在,因此我們可以對這個 Checksum 做點調整,例如取個除以 10 的餘數,26 % 10 = 6
。
——- 1 3 5 7 9 1 ——->
1 + 3 + 5 + 7 + 9 + 1 = 26
26 % 10 = 6
把取完的餘數 6
一起傳過去,接收的時候重新加一下驗證是否等於 6
,如果不是的話,就重新傳送一次。以上例子並非 TCP Checksum 真實的情境,只是把概念用一般人比較容易理解的 10 進制來表示而已。
大致了解 Checksum 之後,你可能會想問,有沒有可能傳的資料錯了,但得出的 Checksum 還是一樣的?
很有可能。
機率大約是 0.0016%。你可能覺得機率蠻低了,但放大到每天不知道多少筆的 TCP 封包在網路上跑著,根據大數法則,發生錯誤沒被揪出來的封包比比皆是。
所以說,Checksum 雖然能揪出大部分的錯誤,但其實算是蠻脆弱的錯誤檢驗機制,現在是依靠著網路模型中其它層也會做的一些錯誤檢測機制,一起和 TCP 避免資料的錯誤產生。
TCP 雖然號稱可靠的傳輸協定,但重點還是擺在讓要傳的封包一定會傳到目的地,或是傳不到也一定讓你知道。
逾時重送、壅塞控制、流量控制
那麼,TCP 要怎麼確保送的封包已經到達目的地了呢?其實方法說起來也很簡單,靠的就是它的內建計時器。
如果我方已經將封包送出一陣子了,還沒得到對方回應說收到,很有可能這個封包在路上就掛了。所以 TCP 會在送出封包後計時,1 秒鐘 2 秒鐘 …,時間到。還沒收到回覆,再送一次。
具體計的時間其實不是固定的數值,剛開始可能從 10 毫秒等起,如果沒得到回覆,下次就等 20 毫秒、40 毫秒,以此類推,這種做法也是因為怕說到目的地的路徑太壅塞了,如果我相同時間一直瘋狂重送封包,可能讓路徑更塞。
有了壅塞的狀況,也可能會有一路暢通,傳的太快讓收的那方措手不及的情形發生,這時 TCP 也會跳出來做流量的控制。
具體怎麼做的呢?就是將來得太快的資料放在如同行李轉盤的記憶體上,慢慢消化,如果轉盤已經放滿資料了,接收方就會叫傳送方先別傳了,等一等再來。
以上為 TCP 對於資料傳輸的簡介,而在傳輸層還有另一大協定 UDP 呢,我們接著來看看。
犧牲可靠性換取速度的 UDP
UDP 為 User Datagram Protocol 的縮寫,中文翻譯成使用者資料報協定。和 TCP 同屬傳輸層,做的事情其實也是類似的,但 UDP 不保證「可靠性」,那麼你可能會有疑問了,既生瑜何生亮,有了 TCP 為何還要 UDP 呢?
我們先從兩者的差異聊起。
UDP vs. TCP
UDP 和 TCP 兩者都有的,就是 Port 連接埠的概念,我們在前面所提到過「兩個設備間的連線可能不只一個,就會需要編號來分開不同的連線」,就是 UDP 和 TCP 共用的概念。
但除此之外,UDP 就像是閹割版的 TCP,其它功能幾乎都沒有。
你說 UDP 也有 TCP Checksum 一樣的 Checksum 呀?同樣也可以檢查是否有可能的資料損壞吧?
這樣說沒錯,但是大部分使用 UDP 這個協定來傳輸資料的,對於資料的正確性通常不會那麼在乎,有的應用會利用 Checksum 的特性意思意思檢查一下損壞,但也有不少應用乾脆就「忽略」這塊,在 UDP 官方定義中,是可選擇忽略的(但建立在 IPv6 上的 UDP 還是必選題)。
其餘的壅塞、流量控制啦,UDP 就通通都不管了,它就是打算以最直接的方式把資料送過去,至於對方有沒有收到就沒它的事了,真是個任性的協定。
UDP 的主要應用
那麼,這樣犧牲可靠性的 UDP 求的是什麼呢?當然就是即時性了。
大部分建立在 UDP 上的應用都分秒必爭。例如串流影音,每秒 30 個影格的影片,掉了幾格一般人根本看不太出來,若是想每格都呈現出來而改用 TCP 的話,造成的後果可能是影片的 lag,為了等沒收到影格重新傳過來,導致後面的影格無法順暢的播出,絕對不會是觀影者希望的事。更何況是一些直播影片了,隔壁都在歡呼了只有你的螢幕畫面還在轉阿轉。
除了串流影音之外,前面文章常見網路問題:DNS 提到應用層的 DNS,也是基於 UDP 的一種協定,但比較特殊的是現在 DNS 的實做幾乎都同時使用 UDP 和 TCP,剛開始預設用 UDP 快速從網域名稱獲取 IP 位置,但發現不夠穩定時,就切成 TCP 傳輸資料。
小結
TCP 和 UDP 的作用,都是基於 IP 上的兩個 IP 位置之間交換資料,由於 Port 連接埠的概念提出,不同的服務就可以用不同的 Port 來建立連線,如 DNS 用 Port 53、HTTP 用 Port 80 等等,兩個 IP 位置間可以根據 Port 來建立多個連線。
而應用程式採用兩個協定中的哪個,就要看應用的類型了,如果追求可靠性,不希望掉封包的話當然就選擇 TCP;追求即時性的話就犧牲一點可靠性採取 UDP。但凡事也沒有絕對,像是 DNS 一樣,也可以在不同情境下選擇使用 TCP 或 UDP。
傳輸層就淺談到此囉,接著我們聊聊應用層的一些常用協定。
參考資料
- Wiki - TCP
- Wiki - 通訊埠
- NotFalse 技術客 - TCP 三向交握
- NotFalse 技術客 - TCP 錯誤控制
- Wiki - Checksum
- NotFalse 技術客 - TCP Checksum
- StackOverflow - Can a TCP checksum fail to detect an error? If yes, how is this dealt with?
- StackExchange - If TCP is a reliable data transfer method, then how come its checksum is not 100% reliable?
- Wiki - UDP
- StackExchange - When do DNS queries use TCP instead of UDP?