目錄
傳輸層
再談端口號
端口號范圍劃分
認識知名端口號
兩個問題
netstat與iostat
pidof
UDP協議
UDP協議格式
UDP數據封裝:
UDP數據分用:
UDP協議的特點
面向數據報
UDP的緩沖區
UDP使用注意事項
基于UDP的應用層協
?
傳輸層
在學習HTTP等應用層協議時,為了便于理解,可以簡單的認為HTTP協議是將請求和響應直接發送到了網絡當中。但實際應用層需要先將數據交給傳輸層,由傳輸層對數據做進一步處理后再將數據繼續向下進行交付,該過程貫穿整個網絡協議棧,最終才能將數據發送到網絡當中。
傳輸層負責可靠性傳輸,確保數據能夠可靠地傳送到目標地址。為了方便理解,在學習傳輸層協議時也可以簡單的認為傳輸層協議是將數據直接發送到了網絡當中。
再談端口號
端口號的作用
端口號(Port)標識一個主機上進行網絡通信的不同的應用程序。當主機從網絡中獲取到數據后,需要自底向上進行數據的交付,而這個數據最終應該交給上層的哪個應用處理程序,就是由該數據當中的目的端口號來決定的。
從網絡中獲取的數據在進行向上交付時,在傳輸層就會提取出該數據對應的目的端口號,進而確定該數據應該交付給當前主機上的哪一個服務進程。
因此端口號是屬于傳輸層的概念的,在傳輸層協議的報頭當中就會包含與端口相關的字段。
五元組標識一個通信
在TCP/IP協議中,用“源IP地址”,“源端口號”,“目的IP地址”,“目的端口號”,“協議號”這樣一個五元組來標識一個通信。
比如有多臺客戶端主機同時訪問服務器,這些客戶端主機上可能有一個客戶端進程,也可能有多個客戶端進程,它們都在訪問同一臺服務器。
而這臺服務器就是通過“源IP地址”,“源端口號”,“目的IP地址”,“目的端口號”,“協議號”來識別一個通信的。
- 先提取出數據當中的目的IP地址和目的端口號,確定該數據是發送給當前服務進程的。
- 然后提取出數據當中的協議號,為該數據提供對應類型的服務。
- 最后提取出數據當中的源IP地址和源端口號,將其作為響應數據的目的IP地址和目的端口號,將響應結果發送給對應的客戶端進程。
通過netstat
命令可以查看到這樣的五元組信息。
其中的 Local?Address 表示的就是源IP地址和源端口號,Foreign Address 表示的就是目的IP地址和目的端口號,而 Proto 表示的就是協議類型。?
協議號 VS 端口號
- 協議號是存在于IP報頭當中的,其長度是8位。協議號指明了數據報所攜帶的數據是使用的何種協議,以便讓目的主機的IP層知道應該將該數據交付給傳輸層的哪個協議進行處理。
- 端口號是存在于UDP和TCP報頭當中的,其長度是16位。端口號的作用是唯一標識一臺主機上的某個進程。
- 協議號是作用于傳輸層和網絡層之間的,而端口號是作用于應用層于傳輸層之間的。
端口號范圍劃分
端口號的長度是16位,因此端口號的范圍是0 ~ 65535:
- 0 ~ 1023:知名端口號。比如HTTP,FTP,SSH等這些廣為使用的應用層協議,它們的端口號都是固定的。
- 1024 ~ 65535:操作系統動態分配的端口號。客戶端程序的端口號就是由操作系統從這個范圍分配的。
認識知名端口號
常見的知名端口號
有些服務器是非常常用的,這些服務器的端口號一般都是固定的:
- ssh服務器,使用22端口。
- ftp服務器,使用21端口。
- telnet服務器,使用23端口。
- http服務器,使用80端口。
- https服務器,使用443端口。
查看知名端口號
我們可以查看/etc/services文件,該文件是記錄網絡服務名和它們對應使用的端口號及協議。
說明一下:?文件中的每一行對應一種服務,它由4個字段組成,每個字段之間用TAB或空格分隔,分別表示“服務名稱”、“使用端口”、“協議名稱”以及“別名”。
兩個問題
一個端口號是否可以被多個進程綁定?
一個端口號絕對不能被多個進程綁定,因為端口號的作用就是唯一標識一個進程,如果綁定一個已經被綁定的端口號,就會出現綁定失敗的問題。
一個進程是否可以綁定多個端口號?
一個進程是可以綁定多個端口號的,這與“端口號必須唯一標識一個進程”是不沖突的,只不過現在這多個端口唯一標識的是同一個進程罷了。
我們限制的是從端口號到進程的唯一性,而沒有要求從進程到端口號也必須滿足唯一性,因此一個進程是可以綁定多個端口號的。
netstat與iostat
netstat命令
netstat?是一個用來查看網絡狀態的重要工具。
其常見的選項如下:
- n:拒絕顯示別名,能顯示數字的全部轉換成數字。
- l:僅列出處于LISTEN(監聽)狀態的服務。
- p:顯示建立相關鏈接的程序名。
- t(tcp):僅顯示tcp相關的選項。
- u(udp):僅顯示udp相關的選項。
- a(all):顯示所有的選項,默認不顯示LISTEN相關。
查看TCP相關的網絡信息時,一般選擇使用nltp組合選項。
而查看UDP相關的網絡信息時,一般選擇使用nlup組合選項。?
如果想查看LISTEN狀態以外的連接信息,可以去掉
l
選項,此時就會將處于其他狀態的連接信息顯示出來。?
?
pidof
pidof
命令可以通過進程名,查看進程id。
獲取多個進程pid并進行kill(需要使用xargs向 kill 可執行程序命令行傳參,如果不使用xargs而只有管道,那么會以標準輸入的形式向 kill 輸入,會報錯)
ps axj | head -1 && ps axj | grep httpd | awk '{print $2}' | xargs kill -9
很麻煩,現在可以直接 pidof 獲取配合kill
命令快速殺死多個進程
pidof httpd | xargs kill -9
?
UDP協議
UDP協議格式
UDP的位置
網絡套接字編程時用到的各種接口,是位于應用層和傳輸層之間的一層系統調用接口,這些接口是系統提供的,我們可以通過這些接口搭建上層應用,比如HTTP。我們經常說HTTP是基于TCP的,實際就是因為HTTP在TCP套接字編程上搭建的。
而socket接口往下的傳輸層實際就是由操作系統管理的,因此UDP是屬于內核當中的,是操作系統本身協議棧自帶的,其代碼不是由上層用戶編寫的,UDP的所有功能都是由操作系統完成,因此網絡也是操作系統的一部分。
我們談論UDP不是只談UDP這個傳輸層協議,而是看上層的哪些應用層協議因為應用場景而采用UDP協議來設計!例如直播、音視頻。
UDP協議格式
UDP協議格式如下:
- 16位源端口號:表示數據從哪里來。
- 16位目的端口號:表示數據要到哪里去。
- 16位UDP長度:表示整個數據報(UDP首部+UDP數據)的長度。
- 16位UDP檢驗和:如果UDP報文的檢驗和出錯,就會直接將報文丟棄。
我們在應用層看到的端口號大部分都是16位的,其根本原因就是因為傳輸層協議當中的端口號就是16位的。
UDP如何將報頭與有效載荷進行分離?
UDP的報頭當中只包含四個字段,每個字段的長度都是16位,總共8字節。因此UDP采用的實際上是一種定長報頭,UDP在讀取報文時讀取完前8個字節后剩下的就都是有效載荷了。這可以體現出UDP是面向數據報的,因為它記錄了有效載荷的長度,而TCP就沒有記錄有效載荷的長度。
UDP如何決定將有效載荷交付給上層的哪一個協議?
UDP上層也有很多應用層協議,因此UDP必須想辦法將有效載荷交給對應的上層協議,也就是交給應用層對應的進程。
應用層的每一個網絡進程都會綁定一個端口號,服務端進程必須顯示綁定一個端口號,客戶端進程則是由系統動態綁定的一個端口號。UDP就是通過報頭當中的目的端口號來找到對應的應用層進程的。
說明一下: 內核中用哈希的方式維護了端口號與進程ID之間的映射關系,因此傳輸層可以通過端口號得到對應的進程ID,進而找到對應的應用層進程。
對于每一層,我們都應該考慮這幾個問題(主要是前兩個)
- 報頭和有效載荷如何分離(定長報頭,直接減去前八個字節就是有效載荷,根據)
- 有效載荷應該交付給哪一個上層協議(目的端口號,因為服務器已經bind端口號了,客戶端也明確知道)
- 認識報頭
- 了解協議周邊問題
UDP緩沖區
UDP沒有發送緩沖區,只有接受緩沖區,因為UDPUDP是無連接協議,發送數據前無需建立連接,也不保證數據到達或順序,因此不需要發送緩沖區來管理連接狀態或重傳數據。并且UDP常用于實時應用(如視頻、語音),這些應用對延遲敏感,發送緩沖區可能增加延遲,影響實時性。
有接收緩沖區是因為一個機器可能會收到多個機器發來的UDP報文,服務器可能來不及處理數據,所以需要一定大小的緩沖區。
如何理解報頭?
操作系統是C語言寫的,而UDP協議又是屬于內核協議棧的(傳輸層、網絡層都在內核中實現),因此UDP協議也一定是用C語言編寫的,UDP報頭實際就是一個位段類型。
例如:
UDP數據封裝:
- 當應用層將數據交給傳輸層后,在傳輸層就會創建一個UDP報頭類型的變量,然后填充報頭當中的各個字段,此時就得到了一個UDP報頭。
- 此時操作系統再在內核當中開辟一塊空間,將UDP報頭和有效載荷拷貝到一起,此時就形成了UDP報文。
UDP數據分用:
- 當傳輸層從下層獲取到一個報文后,就會讀取該報文的錢8個字節,提取出對應的目的端口號。
- 通過目的端口號找到對應的上層應用層進程,然后將剩下的有效載荷向上交付給該應用層進程。
?
UDP協議的特點
UDP傳輸的過程就類似于寄信,其特點如下:
- 無連接:知道對端的IP和端口號就直接進行數據傳輸,不需要建立連接。
- 不可靠:沒有確認機制,沒有重傳機制;如果因為網絡故障該段無法發到對方,UDP協議層也不會給應用層返回任何錯誤信息。
- 面向數據報:不能夠靈活的控制讀寫數據的次數和數量。發送方發了幾次,接收方就需要接收幾次。
注意: 報文在網絡中進行路由轉發時,并不是每一個報文選擇的路由路徑都是一樣的,因此報文發送的順序和接收的順序可能是不同的。
既然報頭是一個結構體類型,那么它就可以定義變量,為變量開辟空間,就可以和有效載荷進行合并,構建一個結構體,那么在不管在服務端OS還是客戶端OS,它內部一定會存在大量的UDP報文,操作系統需要對這些UDP報文做管理,也就還是“先描述、再組織”,用結構體描述一個UDP報文,用鏈表管理,這樣一來操作系統對Udp報文的管理就變成了對鏈表的增刪查改,當UDP報文充滿了接收緩沖區,后來的UDP報文就直接丟棄,那么這個丟棄的動作其實就是對鏈表的刪除操作!
應用層其實就是對字符串的處理工作,獲取整個報文、去報頭、序列化反序列化這一類操作。
面向數據報
應用層交給UDP多長的報文,UDP就原樣發送,既不會拆分,也不會合并,這就叫做面向數據報。
比如用UDP傳輸100個字節的數據:
- 如果發送端調用一次sendto,發送100字節,那么接收端也必須調用對應的一次recvfrom,接收100個字節;而不能循環調用10次recvfrom,每次接收10個字節。
UDP的緩沖區
- UDP沒有真正意義上的發送緩沖區。調用sendto會直接交給內核,由內核將數據傳給網絡層協議進行后續的傳輸動作。
- UDP具有接收緩沖區。但是這個接收緩沖區不能保證收到的UDP報的順序和發送UDP報的順序一致;如果緩沖區滿了,再到達的UDP數據就會被丟棄。
- UDP的socket既能讀,也能寫,因此UDP是全雙工的。
為什么UDP要有接收緩沖區?
如果UDP沒有接收緩沖區,那么就要求上層及時將UDP獲取到的報文讀取上去,如果一個報文在UDP沒有被讀取,那么此時UDP從底層獲取上來的報文數據就會被迫丟棄。
一個報文從一臺主機傳輸到另一臺主機,在傳輸過程中會消耗主機資源和網絡資源。如果UDP收到一個報文后僅僅因為上次收到的報文沒有被上層讀取,而被迫丟棄一個可能并沒有錯誤的報文,這就是在浪費主機資源和網絡資源。
因此UDP本身是會維護一個接收緩沖區的,當有新的UDP報文到來時就會把這個報文放到接收緩沖區當中,此時上層在讀數據的時就直接從這個接收緩沖區當中進行讀取就行了,而如果UDP接收緩沖區當中沒有數據那上層在讀取時就會被阻塞。因此UDP的接收緩沖區的作用就是,將接收到的報文暫時的保存起來,供上層讀取。這里就是一個生產者消費者模型,在內核中會定義自旋鎖進行加鎖管理!
UDP使用注意事項
需要注意的是,UDP協議報頭當中的UDP最大長度是16位的,因此一個UDP報文的最大長度是64K(包含UDP報頭的大小)。
然而64K在當今的互聯網環境下,是一個非常小的數字。如果需要傳輸的數據超過64K,就需要在應用層進行手動分包,多次發送,并在接收端進行手動拼裝。
基于UDP的應用層協議
- NFS:網絡文件系統。
- TFTP:簡單文件傳輸協議。
- DHCP:動態主機配置協議。
- BOOTP:啟動協議(用于無盤設備啟動)。
- DNS:域名解析協議。
當然,也包括你自己寫UDP程序時自定義的應用層協議。