四樓的樓上就是五六七樓挑高樓層了,一般我們都直接以七樓稱呼它,也就是應用層 (Application Layer),應用層協定需要進行程序與程序之間的通訊 (Process-to-Process Communication),因此,四樓需要提供給它樓上的服務通常有以下幾種:
1. Process-to-process communication
2. Integrity check
3. Reliable data transfer
4. Flow control
5. Congestion control
我們分別來看看這幾種服務與 UDP 和 TCP。
Process-to-Process Communication
先來說說 Process-to-Process Communication,一台電腦上可能有許多的網路應用程式,這些應用程式將自身的資料傳遞給作業系統,透過 UDP 或 TCP 來將資料彙整起來,變成統一的管道。可以想像一下,每一個應用程式就是一個管道,許多的應用程式就有許多的管道,然後這些管道都在 TCP 和 UDP 裡頭彙整起來,最後從網路卡與網路線出去的資料,只有一個管道,這種由多管道變成單一管道的過程,我們叫它做 demultiplexing。實務上,每一個應用程式都可以擁有一個以上的管道,總而言之七樓傳來的管道很多就是了,而四樓必須負責把這些管道彙整成一條,以至於以下三樓或二樓都是看到一條管道。資料透過網路線傳送出去,到達目的地的電腦,目的地電腦的四樓,不管是 UDP 或 TCP,必須把這單一管道,分成原先的多管道,然後傳給樓上。這種從單一管道變成多管道的過程,我們叫做 multiplexing。
所以可以知道,要能夠透過網路提供程序間的通訊 (Process-to-Process Communication),就必須要提供 multiplexing 和 demultiplexing 的服務。
網路第四層透過 IP 位址和通訊埠 (Port) 來達到這個目的。
{來源 IP,來源通訊埠,目的 IP,目的通訊埠} 這四個資訊綁成一組,一組就代表一條七樓的管道,所以只需要將這資訊放在 UDP 和 TCP 的表頭裡面,就可以作到 multiplexing 和 demultiplexing 了。
實務上,作業系統使用 Socket 來實踐七樓的管道,應用程式透過使用 Socket API (Application Programming Interface) 來完成演算法。
Integrity Check
下一項服務 Integrity Check,是將封包資料,用 1's Complement 的方法做一個 Checksum,傳送出去後到目的地,再檢查這個 Checksum,以此驗證封包內容是否有發生傳輸錯誤的情況。UDP (User Datagram Protocol)
UDP 也就只提供上述這兩項服務:Process-to-Process Communication 和 Integrity Check。所以 UDP 的表頭很簡單,只包含了來源通訊埠、目的通訊埠、封包長度、以及 Checksum 這四個欄位,每個各 2 bytes,總共加起來 8 bytes。至於 IP 位址,由更底層的三樓 IP 表頭來完成。UDP 的優點
UDP 的好處在於以下幾點:1. 應用程式擁有更多的主控權,因為 UDP 不像 TCP 一樣自動限制流量,所以使用 UDP 可以隨心所欲的傳輸資料,想傳多少就傳多少,想什麼時候停就什麼時候停。也因此相當多的即時影音應用會透過 UDP 傳送資料,DoS 攻擊透過 UDP 也是很常發生的事。
2. 不需要建立連線,TCP 的連線建立常常是網路速度慢的原因之一,畢竟至少就少了整整一個 Round-time Trip 時間可以傳輸資料,加上考慮 Pipelining,速度的確有差。例如如果整個 DNS 都是在 TCP 上面跑,網路速度可能會慢很多。
3. 不需維護連線所需要的資源,TCP 連線有許多的狀態和變數,都由作業系統負責配置與維護,UDP 就不需要了,省下系統資源。
4. 表頭比較小,TCP 最小的表頭大小為 20 bytes,UDP 統一規格只有 8 bytes,網路負擔比較小。
以上是我們對 UDP 的簡介,接著來看其他服務以及 TCP。
Reliable Data Transfer
這或許是 TCP 最複雜的一部分,也就是提供可靠的資料傳輸服務,所謂可靠,是代表所傳輸的資料會按照順序,完整地到達目的地,順序不會亂,資料也不會不見或者傳錯。要達到這項服務,需要透過幾個技術來完成,這裡只簡介觀念。
首先需要透過 Checksum 和 Acknowledgement 來確定資料沒有傳錯,Checksum 前面介紹過,Acknowledgement 技術就是接收方在接收到資料後,如果資料正確,就傳輸 ACK (ACKnowledgement) 封包回去,如果錯了,就傳輸 NAK (Non-AcKnowledgement) 給對方,請它重傳,實務上 NAK 可以用前一個的 ACK 來做,所以只需要 ACK 就可。
但是 ACK 封包也可能傳錯,所以需要再加上 Sequence Number (以下以 SYN 表示) 機制來限定重傳的封包。傳送方送資料前,在資料上面印上記號,就是 Sequence 的功能,每一個 ACK 都是對應前一個 SYN,代表接收方說「我收到上面帶有某某 SYN 記號的封包了」,所以如果 ACK 有錯,或者順序有錯,傳送方就會重傳帶有前一個 SYN 記號的封包。所以 SYN 技術是為了解決 ACK 也會傳錯的問題才首先加入的,等一下我們會看到,為了效能的緣故,SYN 也可以扮演加速的功能。
另外也可能網路壅塞,或者發生未知問題,封包根本送不到對方,所以要加上 Timer 技術,設定說如果時間太久都沒有聽到 ACK 回應,就重傳資料,如果一直重傳還是沒回應,就通知上層說網路有問題。Timer 技術解決太久沒回應的問題。
小小總結一下,Reliable Data Transfer (RDT) 服務可以透過 Checksum、ACK、SYN,以及 Timer 這些技術來達到。事實上,不管是不是 TCP,要提供 RDT 服務,大概都需要這些機制才能完成。
Pipelining
不過,只有以上那些機制,網路的速度會相當慢,應該傳送方總是必須等待接收方傳回 ACK 才能夠再傳下一個封包,所以我們通常會加上 Pipelining 機制,類似批次執行的概念,一次傳多一點,讓傳送方和接收方中間的管子,也就是網路,盡可能不要閒置下來。Pipelining 機制常見有兩種,分別是 Go-Back-N 和 Selective Repeat,一樣,以下還是只介紹觀念。
Go-Back-N
觀念很簡單,以下圖示代表傳送方:(X) (Y)
| |
V V
| | | | | | | | | | | | | | | | | ...
x x x x ? ? ? ? o o o o - - - - - ...
\ /
----- N -----
假設 | 符號代表一個又一個傳輸的封包,封包下面的符號有 x, ?, o, - 分別是 x 代表已經傳送並且得到 ACK 的封包,? 代表已經傳送卻還未接受到 ACK 的封包,o 代表尚未傳送的封包,? 和 o 的總和為 N,超過 N 範圍的封包用符號 - 表示。
封包上面的有兩個變數 X 和 Y,X 代表基底 (Base),Y 代表下一個可以傳送的 SYN (NextSyn),所以封包可以分成四類 x, ?, o, 和 -,? 的範圍介在 [Base, NextSyn - Base],o 介在 [NextSyn, Base - N +1]。
傳送方根據應用軟體的需要,一次最多可以傳送的封包範圍就是 N,只有當最小的 ? 封包得到 ACK,N 才有可能往前移動,就像一個滑動的視窗 (Sliding Window)。
接收方所送回的 ACK,有累積 (Cumulative) 的特性,也就是只會傳送成功按照順序接收到的封包的最大 SYN,舉例來說,上面有 4 個 ? 封包,代表已經有 4 個送出去的封包,還沒有收到 ACK,如果第 3 個封包中途掉了,即使第 4 個封包有送達到接收方,成功接收到的封包最大 SYN 只有到第 2 個而已,因此即使收到第 4 個封包,接收方也只是重傳 SYN 2,Timer 的時間到了之後,第 3 和第 4 個封包都會被重傳。
Selective Repeat
接續 Go-Back-N 的例子,Selective Repeat 就是只會重傳掉了的那個第 3 個封包,前提是接收端也要在接收到第 4 個封包的時候回傳 ACK 4。你可以想像,假設 N 很大,傳送端也一次送出大量的封包,假設只是最前面的幾個封包掉了,後面 90% 以上的封包都正確接收了,Go-Back-N 還是會重傳它們!Selective Repeat 就是只會重傳掉失的部份而已。
由此可以看出,Selective Repeat 比 Go-Back-N 有效率,但是也比較複雜,而且 Selective Repeat 的 ACK 就沒有累積 (Cumulative) 特性了。
TCP 的 Pipelining 機制是 Go-Back-N 和 Selective Repeat 的混合體。實作上 TCP 有不同的版本,最原始的版本比較接近 Go-Back-N,但是為了效率考量,陸續有其他的版本像 Selective Repeat 靠攏,因此說它是兩種的混合體。
再小小總結一下,SYN、ACK、Timer、和 N 這幾種機制結合起來,就是 TCP 的 Pipelining 機制,也是讓它更能有效率的運用網路資源的原因。
我們稍微多說一點 N,或許你會問:「為什麼要有 N 呢?」的確,如果沒有 N,傳送端沒有限制的一直傳就好了,很爽快!加上 N 這個最大上限的考慮是和我們要討論的最後兩個服務有關,也就是 Flow Control 和 Congestion Control。
Flow Control
Flow Control 和 Congestion Control 不同,Flow Control 主要是避免傳送端塞爆接收端的緩衝區,而 Congestion Control 則是避免傳送端把網路整個塞爆。受限於網路硬體限制,資料在網路實體媒介上傳輸是有最大尺寸上限的,這個尺寸上限跟不同的實體媒介有關,通常我們稱這個尺寸為最大傳輸單位 MTU (Maximum Transmission Unit)。TCP 在傳輸資料前,會考慮 MTU,加上網路的表頭 (Header),制定 MSS (Maximum Segment Size),也就是一個 TCP 封包所能帶的最大內容資料量,如果應用軟體要傳輸的大小超過 MSS,就會將其切割,並傳遞給下層。
同樣的,接收端在收到資料時,也是將表頭剝開後,將內容資料傳遞給對應的上層,你可以想像,假設上層接收得很慢,但是下層的資料一直進來,該怎麼辦呢?辦法就是在接收端的 TCP 這裡預備一個緩衝區 (Buffer),將網路資料先儲存在緩衝區內,然後同時也通知應用軟體來接收。你可以想像這個緩衝區,在網路資料傳輸的過程中一定會變來變去,隨著應用軟體取走資料,以及下層網路傳來資料的速率而改變,我們把緩衝區可用的空間變數定為 Receive Window (rwnd),這個變數代表當下瞬間,接收端還有多少可用的空間,可以讓網路資料塞放。
考慮一種情況,傳送端傳送的太快了,但是接收端的上層收得超慢,以至於接收端的 rwnd 很快就暴掉了,變成 0,為了要避免這種狀況,就需要 Flow Control 的機制。
接收端在 ACK 裡面放入 rwnd 變數資訊,告訴傳送端:「我這裡剩下空間很少,你一次不要傳太多來!」,或者是「我這裡空間大得很,儘管來吧!」
傳送端的 N(就是上面提過的 N)就有這個限制:N <= rwnd,只要滿足,就不至於塞爆對方的緩衝區,當塞爆了,傳送端會定時送出大小為 1 的探測封包,只要 rwnd 一變大(隨著應用軟體把資料取走),回給探測封包的 ACK 就會附帶新的 rwnd 值。
Congestion Control
Congestion Control 有點像是公德心,也有點像是環保的態度,避免自己把整個網路的頻寬給佔滿了,TCP 就是有這種機制的好協定。Congestion Control 通常實踐上有兩種方式,一種是透過網路中間的設備所回饋的資訊來完成,例如 ATM (Asynchronous Transfer Mode) 網路,另一種是設備不會告訴你,你要自己猜的作法,也就是 IP (Internet Protocol) 網路的作法。
為什麼說猜呢?因為網路封包一旦離開本機,在世界上各個不同的路由器和網域中傳送,誰知道哪裡發生了什麼事啊?如果沒人告訴你,當然本機端只能夠用「猜」的囉!
猜的方法是透過掉封包這個重要的現象來判斷,掉封包的情況有兩種,一種是傳送端的 Timer 時間到了,也就是 Timeout,所以傳送端認為封包掉了因此重傳;另一種是接收端送回來的 ACK 封包,都是回應舊的 SYN,而不是最後送出的 SYN,而且這樣的 ACK 還重複送了好幾個!(實作上通常是重複 3 個),也就是 Duplicate ACKs。
當發生上述兩種任何一種現象時,代表封包掉了,這個時候極有可能是網路發生壅塞,需要處理。
怎麼處理呢?傳送端最能夠做的,就是調整傳輸的速度,當可能發生壅塞時,傳得慢一點,當天下太平時,為了兼顧效能和網路資源使用率,就傳得快一點。
傳送端使用一個變數 Congestion Window (cwnd),加上三種不同的速度模式:Slow Start、Congestion Avoidance,以及 Fast Recovery,來實作 Congestion Control。
預設 cwnd 為 1 MSS,速度模式為 Slow Start,雖然名字有 slow,但是執行起來可不慢,只要網路沒有阻塞,也就是正常收到接收端來的 ACK,cwnd 就等於 2 * cwnd,因此三次來回後,cwnd 就等於 4 MSS,n 次來回後,cwnd 等於 2^(n-1) MSS,你可以看到它是指數成長,速度很快。
當第一次發生 Timeout 事件時,就設定另一變數 Slow Start Threshold 等於 cwnd/2,也就是發生掉封包前的最後一個有效的 cwnd 值,然後 cwnd 重設為 1,重新開始 Slow Start。
下一次當 cwnd 長到 Threshold 後的時候,就進入 Congestion Avoidance 模式,這時候一次 cwnd 只增加 MSS * (MSS/cwnd) bytes,當又發生 Timeout 時,就又回到 cwnd = 1,並回到 Slow Start。
後來 TCP 不同的版本加入了 Fast Recovery,也就是當掉封包的情況,不是 Timeout,而是 Duplicate ACKs 時,就短暫的進入 Fast Recovery 模式,此時先設定 cwnd = Threshold,然後每收到一個 Duplicate ACK,就將 cwnd 加 1,直到收到新的 ACK,才進入 Congestion Avoidance 模式,當然,如果又發生 Timeout 事件,就又回到 Slow Start。
總結一下,透過 cwnd、Slow Start、Congestion Avoidance,以及 Fast Recovery,TCP 實作 Congestion Control 技術。
還記得我們之前提到的 N 嗎?現在 N 的條件式修改為:N <= min {cwnd, rwnd}
因此 Pipelining 機制的最大上限 N,受限於 Flow Control 的 rwnd 以及 Congestion Control 的 cwnd。
以上大致是我們關於 Flow Control 和 Congestion Control 的介紹。
TCP (Transmission Control Protocol)
TCP 除了 UDP 所提供的 Process-to-Process Communication 和 Integrity Check 以外,也提供我們後來介紹的 Reliable Data Transfer、Flow Control,以及 Congestion Control 服務。實務上,TCP 的研究相當豐富,有些也很複雜,但是這裡的介紹,應該可以提供一個完整的概念。TCP 表頭的格式
TCP 表頭最小為 20 位元組,除了通訊埠欄位外,以下我們簡介幾個最重要的欄位。0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+(圖片來源:http://www.freesoft.org/CIE/Course/Section4/8.htm)
Sequence Number:這就是我們上面所述的 SYN。
Acknowledgement Number:我們上面所述的 ACK。
Window:我們上面所述的 rwnd。
值得注意的是,表頭中有 6 個 bit,分別是 URG, ACK, PSH, RST, SYN, FIN,不要將表頭裡的 ACK bit 和 SYN bit 與我們上面所述的 SYN number 和 ACK number 混為一談!這裡的 6 個 bit 分別代表封包的狀態,也是以下我們所要簡介的。
TCP 的狀態
TCP 連線包括幾種狀態,我們簡介兩種最常的使用情境,一種是連線建立,另一種是連線結束。我們假設 Server-Client 架構。
連線建立時,Client 送出 SYN bit on 的封包,也就是 SYN bit 被設定為 1,其他 bits 為 0,我們常說這個首先的封包叫做 SYN 封包,Client 進入 SYN_SENT 狀態;Server 收到後,送回 SYN bit 和 ACK bit 皆為 on 的封包,我們常說這個第二個封包叫做 SYN-ACK 封包,Server 進入 SYN_RCVD 狀態;Client 接收到後,送出 ACK bit on 的封包,這時候 SYN bit 與其他的狀態 bits 皆為 off,我們常說這第三個封包為 ACK 封包,Client 進入 Established 狀態,Server 在收到第三個 ACK 封包後,也進入 Established 狀態。
到此,三個封包來往之後,我們稱此 TCP 連線已建立 (Established),這個過程也常被稱作 3-Way Handshake。
通常第一和第二個封包都不帶資料內容,第三個以後才可能攜帶內容。
連線結束時,我們假設是 Client 端要結束,首先它送出 FIN bit on 封包,Client 進入 FIN_WAIT_1 狀態;Server 接受到後,送回 ACK bit on 和 FIN bit on 封包,這可能是分兩次送,也可能一次送但兩個 bits 都 on,當送出 ACK bit on 封包時,Server 進入 CLOSE_WAIT 狀態,送出 FIN bit on 時,進入 LAST_ACK 狀態;當 Client 接收到 ACK bit on 封包時,進入 FIN_WAIT_2,當收到 FIN bit on 封包時,進入 TIME_WAIT 狀態,並送出最後的 ACK bit on 封包,TIME_WAIT 預設會等待 30 秒;當 Server 收到最後的 ACK 封包時,進入 CLOSED 狀態,對它來說,連線正式結束,Client 在等待 TIME_WAIT 結束後,也會自動進入 CLOSED 狀態,正式結束連線。
以上,就是我們對於 TCP 的介紹。
這樣,我們就把四樓裡美好的兩種協定 TCP 和 UDP 介紹完畢了。許多網路安全機制都與四樓很有關系,例如 SSL/TLS,就是綁在 TCP 上面的服務,而有不少 DoS 威脅,是針對 TCP 的機制弱點來攻擊之;另外 UDP 則在 DoS 威脅中常被利用,和 DNS 相關的許多威脅,也是走 UDP 的。
關於 UDP DoS (Denial of Service),有一點我們可以知道,因為 UDP 沒有連線狀態的概念,因此頂多只能計算某一來源 IP 在單位時間內送來多少封包量,無法用連線數目來限制它,這一點和 TCP 防範 DoS 的思維不同。
不好意思 demultiplexing 和 multiplexing是不是說相反了
回覆刪除感謝!觀念終於釐清了
回覆刪除感謝分享!寫得真好!
回覆刪除