文章目錄
- Ⅰ. 傳輸層概述
- 1、進程之間的通信
- 2、再談端口號
- 端口號的引出
- 五元組標識一個通信
- 端口號范圍劃分
- 常見的知名端口號
- 查看知名端口號
- 協議號 VS 端口號
- 3、兩個問題
- 一個端口號是否可以被多個進程綁定?
- 一個進程是否可以綁定多個端口號?
- 4、部分常見指令
- pidof(用于查看進程id)
- netstat(查看網絡狀態)
- Ⅱ. UDP協議
- 1、UDP協議所處位置
- 2、UDP協議格式
- 如何理解首部?
- UDP協議如何將首部與有效載荷進行分離?
- UDP協議如何決定將有效載荷交付給上層的哪一個協議?
- 3、UDP的主要特點
- 4、面向數據報
- 5、UDP協議的緩沖區
- 為什么UDP要有接收緩沖區?
- 6、基于UDP的應用層協議

Ⅰ. 傳輸層概述
1、進程之間的通信
? 在學習 HTTP
等應用層協議時,為了便于理解,可以簡單的認為 HTTP
協議是將請求和響應直接發送到了網絡當中。但實際應用層需要先將數據交給傳輸層,再由傳輸層對數據做進一步處理后再將數據繼續向下進行交付,該過程貫穿整個網絡協議棧,最終才能將數據發送到網絡當中。
? 傳輸層負責可靠性傳輸,確保數據能夠可靠地傳送到目標地址。從通信和信息處理的角度看,運輸層為它上面的應用層提供通信服務!
? 但是我們要明確的是,真正進行通信的實體,其實是主機中的應用進程,也就是進程之間的通信!而為了達到傳輸層向上服務應用層的時候,可以找到對應的進程,就有了兩個重要的功能:復用和分用!如下圖所示:
? 此外,傳輸層還要對收到的報文進行差錯檢測,只不過 傳輸層只檢驗首部是否出現差錯,而不檢查有效載荷部分!
2、再談端口號
端口號的引出
? 應用層所有的應用進程都可以通過運輸層再傳送到網絡層,這叫做復用;而運輸層從網絡層收到發送給各應用進程的數據后,必須分別交付指明的各應用進程,這就是分用。
? 所以很明顯,給應用層的每個應用進程賦予一個非常明確唯一的標志是至關重要的!
? 我們知道,一臺計算機中的進程有著唯一標識的進程標識符,但因為這個進程標識符和操作系統是強相關的,如果我們將其作為復用和分用的標識的話,那么會有一個問題,就是一個進程的標識符由操作系統管理,所以進程的銷毀和創建都會導致進程標識符的變化,但是我們又是希望在網絡中傳輸的時候,對方的唯一標志可以是盡量保持不變的(因為一旦變化,請求連接的標識也需要改變),所以我們 不能用進程標識符作為復用和分用的唯一標志!
? 所以此時就有人使用了端口號這種方案來作為唯一標識!
? 端口號(Port
)標識一個主機上進行網絡通信的不同的應用程序。當主機從網絡中獲取到數據后,需要自底向上進行數據的交付,而這個數據最終應該交給上層的哪個應用處理程序,就是由該數據當中的目的端口號來決定的。
? 從網絡中獲取的數據在進行向上交付時,在傳輸層就會提取出該數據對應的目的端口號,進而確定該數據應該交付給當前主機上的哪一個服務進程。
? 因此端口號是屬于傳輸層的概念的,在傳輸層協議的報頭當中就會包含與端口相關的字段。
? 請注意,端口號只具有本地意義,在互聯網不同的計算機中,相同的端口號是沒有關聯的!
五元組標識一個通信
? 在 TCP/IP
協議中,用 “源IP地址”、“源端口號”、“目的IP地址”、“目的端口號”、“協議號” 這樣一個五元組來標識一個通信。
? 比如有多臺客戶端主機同時訪問服務器,這些客戶端主機上可能有一個客戶端進程,也可能有多個客戶端進程,它們都在訪問同一臺服務器。
而這臺服務器就是通過 “源IP地址”、“源端口號”、“目的IP地址”、“目的端口號”、“協議號” 來識別一個通信的。
- 先提取出數據當中的目的
IP
地址和目的端口號,確定該數據是發送給當前服務進程的。 - 然后提取出數據當中的協議號,為該數據提供對應類型的服務。
- 最后提取出數據當中的源
IP
地址和源端口號,將其作為響應數據的目的IP地址和目的端口號,將響應結果發送給對應的客戶端進程。
? 通過 netstat
命令可以查看到這樣的五元組信息。
? 其中的 Local Address
表示的就是源IP地址和源端口號,Foreign Address
表示的就是目的IP地址和目的端口號,而 Proto
表示的就是協議類型。
端口號范圍劃分
端口號的長度是 16
位,因此端口號的范圍是 0 ~ 65535
:
0 ~ 1023
:知名端口號。比如HTTP
、FTP
、SSH
等這些廣為使用的應用層協議,它們的端口號都是固定的。1024 ~ 65535
:操作系統動態分配的端口號。客戶端程序的端口號就是由操作系統從這個范圍分配的。
常見的知名端口號
有些服務器是非常常用的,這些服務器的端口號一般都是固定的:
ssh
服務器,使用22
端口ftp
服務器,使用21
端口telnet
服務器,使用23
端口dns
服務器,使用53
端口http
服務器,使用80
端口https
服務器,使用443
端口
查看知名端口號
? 我們可以查看 /etc/services
文件,該文件是記錄網絡服務名和它們對應使用的端口號及協議。
? 說明一下:文件中的每一行對應一種服務,它由 4
個字段組成,每個字段之間用 TAB
或空格分隔,分別表示“服務名稱”、“使用端口”、“協議名稱”以及“別名”。
協議號 VS 端口號
- 協議號是存在于
IP
報頭當中的,其長度是8
位。協議號指明了數據報所攜帶的數據是使用的何種協議,以便讓目的主機的IP
層知道應該將該數據交付給傳輸層的哪個協議進行處理。 - 端口號是存在于
UDP
和TCP
報頭當中的,其長度是16
位。端口號的作用是唯一標識一臺主機上的某個進程。 - 協議號是作用于傳輸層和網絡層之間的,而端口號是作用于應用層于傳輸層之間的。
3、兩個問題
一個端口號是否可以被多個進程綁定?
? 一個端口號絕對不能被多個進程綁定,因為端口號的作用就是唯一標識一個進程,如果綁定一個已經被綁定的端口號,就會出現綁定失敗的問題。
一個進程是否可以綁定多個端口號?
? 一個進程是可以綁定多個端口號的,這與“端口號必須唯一標識一個進程”是不沖突的,只不過現在這多個端口唯一標識的是同一個進程罷了。
? 我們限制的是從端口號到進程的唯一性,而沒有要求從進程到端口號也必須滿足唯一性,因此一個進程是可以綁定多個端口號的。
4、部分常見指令
pidof(用于查看進程id)
pidof httpServer | xargs kill -9 // xargs用于將管道前面獲取的參數追加到該指令后面
netstat(查看網絡狀態)
n 拒絕顯示別名,能顯示數字的全部轉化成數字
l 僅列出有在 Listen (監聽) 的服務狀態
p 顯示建立相關鏈接的程序名
t(tcp) 僅顯示tcp相關選項
u(udp) 僅顯示udp相關選項
a(all) 顯示所有選項,默認不顯示LISTEN相關
Ⅱ. UDP協議
1、UDP協議所處位置
? 網絡套接字編程時用到的各種接口,是位于應用層和傳輸層之間的一層系統調用接口,這些接口是系統提供的,我們可以通過這些接口搭建上層應用,比如 HTTP
。我們經常說 HTTP
是基于 TCP
的,實際就是因為 HTTP
在 TCP
套接字編程上搭建的。
? 而 socket
接口往下的傳輸層實際就是由操作系統管理的,因此 UDP
是屬于內核當中的,是操作系統本身協議棧自帶的,其代碼不是由上層用戶編寫的,UDP
的所有功能都是由操作系統完成,因此網絡也是操作系統的一部分。
2、UDP協議格式
? 其格式如下:
16
位源端口號:表示數據從哪里來。16
位目的端口號:表示數據要到哪里去。16
位整個報文長度:表示整個數據報(UDP
首部 +UDP
數據)的長度。- 這也就說明
UDP
最大可傳輸的長度為2^16
即64KB
(包含首部字段),如果需要 傳輸大于64KB
的數據,就需要應用層多次分包,并在接收端手動拼裝。
- 這也就說明
16
位檢驗和:如果UDP
報文的檢驗和出錯,就會直接將報文丟棄。
? 之所以我們在應用層看到的端口號大部分都是 16
位的,比如使用 uint16_t
類型,其根本原因就是因為傳輸層協議當中的端口號就是 16
位的。
如何理解首部?
? 操作系統是 C
語言寫的,而 UDP
協議又是屬于內核協議棧的,因此 UDP
協議也一定是用 C
語言編寫的,所以 UDP
首部本質上是一個結構體對象或者包含位段的結構體,如下所示:
struct udphdr {uint16_t uh_sport; /* 源端口號 */uint16_t uh_dport; /* 目的端口號 */uint16_t uh_ulen; /* UDP數據報長度(包括頭部+數據) */uint16_t uh_sum; /* 數據校驗和 */
};
UDP數據封裝:
- 當應用層將數據交給傳輸層后,在傳輸層就會創建一個
UDP
報頭類型的變量,然后填充報頭當中的各個字段,此時就得到了一個UDP
報頭。 - 此時操作系統再在內核當中開辟一塊空間,將
UDP
報頭和有效載荷拷貝到一起,此時就形成了UDP
報文。
UDP數據分用:
- 當傳輸層從下層獲取到一個報文后,就會讀取該報文的前
8
個字節,提取出對應的目的端口號。 - 通過目的端口號找到對應的上層應用層進程,然后將剩下的有效載荷向上交付給該應用層進程。
UDP協議如何將首部與有效載荷進行分離?
? UDP
的報頭當中只包含四個字段,每個字段的長度都是 16
位,總共 8
字節。因此 UDP
采用的實際上是一種定長報頭,UDP
在讀取報文時讀取完前 8
個字節后剩下的就都是有效載荷了。
? 而我們只需要提取報頭中的 數據報長度 字段,減去 8
個字節,最后的大小就是有效載荷的長度,是可以直接讀取上來的!
UDP協議如何決定將有效載荷交付給上層的哪一個協議?
? UDP
上層也有很多應用層協議,因此 UDP
必須想辦法將有效載荷交給對應的上層協議,也就是交給應用層對應的進程。
? 應用層的每一個網絡進程都會綁定一個端口號,服務端進程必須顯示綁定一個端口號,客戶端進程則是由系統動態綁定的一個端口號。UDP
就是通過報頭當中的目的端口號來找到對應的應用層進程的。
? 說明一下: 內核中用哈希的方式維護了端口號與進程
ID
之間的映射關系,因此傳輸層可以通過端口號得到對應的進程ID
,進而找到對應的應用層進程。
3、UDP的主要特點
- 無連接。發送數據之前不需要建立連接。
- 使用盡最大努力交付。即 不保證可靠交付。
- 面向報文。
UDP
一次傳送和交付一個完整的報文。 - 沒有擁塞控制。網絡出現的擁塞不會使源主機的發送速率降低。很適合多媒體通信的要求。
- 支持一對一、一對多、多對一、多對多等交互通信。
- 首部開銷小,只有
8
個字節。
? 總結一點,就是【簡單方便,但不可靠】。
? 此外,應用程序必須選擇合適大小的報文。若報文太長,IP
層在傳送時可能要進行分片,降低 IP
層的效率。若報文太短,會使 IP
數據報的首部的相對長度太大,降低 IP
層的效率。
4、面向數據報
? 應用層交給 UDP
多長的報文,UDP
就原樣發送,既不會拆分,也不會合并,這就叫做面向數據報。
? 比如用 UDP
傳輸 100
個字節的數據:
? 如果發送端調用一次 sendto
,發送 100
字節,那么接收端也必須調用對應的一次 recvfrom
,接收 100
個字節,而不能循環調用 10
次 recvfrom
去每次接收 10
個字節。
5、UDP協議的緩沖區
? UDP
協議不需要考慮多個報文之間的粘連問題,因為 UDP
沒有真正意義上的發送緩沖區。調用 sendto
函數會直接交給內核(應用層發一個,傳輸層送走一個),由內核將數據傳給網絡層協議進行后續的傳輸動作。
? 但是 UDP
具有接收緩沖區。但是這個接收緩沖區不能保證收到的 UDP
報的順序和發送 UDP
報的順序一致。如果緩沖區滿了,再到達的 UDP
數據就會直接被丟棄,所以 UDP
協議是一種不可靠、全雙工的協議。
為什么UDP要有接收緩沖區?
? 如果 UDP
沒有接收緩沖區,那么就要求上層及時將 UDP
獲取到的報文讀取上去,如果一個報文在 UDP
沒有被讀取,那么此時 UDP
從底層獲取上來的報文數據就會被迫丟棄。
? 一個報文從一臺主機傳輸到另一臺主機,在傳輸過程中會消耗主機資源和網絡資源。如果 UDP
收到一個報文后僅僅因為上次收到的報文沒有被上層讀取,而被迫丟棄一個可能并沒有錯誤的報文,這就是在 浪費主機資源和網絡資源。
? 因此 UDP
本身是會維護一個接收緩沖區的,當有新的 UDP
報文到來時就會把這個報文放到接收緩沖區當中,此時上層在讀數據的時就直接從這個接收緩沖區當中進行讀取就行了,而如果 UDP
接收緩沖區當中沒有數據那上層在讀取時就會被阻塞。因此 UDP
的接收緩沖區的作用就是,將接收到的報文暫時的保存起來,供上層讀取。
6、基于UDP的應用層協議
NFS
:網絡文件系統TFTP
:簡單文件傳輸協議DHCP
:動態主機配置協議BOOTP
:啟動協議(用于無盤設備啟動)DNS
:域名解析協議
當然,也包括自己寫 UDP
程序時自定義的應用層協議。