傳輸層協議負責將數據從發送端傳輸到接收端。
一、再談端口號
端口號標識了一個主機上進行通信的不同的應用程序。在 TCP/IP 協議中,用 "源IP","源端口號","目的 IP","目的端口號","協議號" 這樣一個五元組來標識一個通信?(可以通過 netstat -n 查看)。
1.1 端口號范圍劃分
? 0 - 1023: 知名端口號,HTTP、FTP、SSH 等這些廣為使用的應用層協議的端口號都是固定的。
? 1024 - 65535:操作系統動態分配的端口號,客戶端程序的端口號就是由操作系統從這個范圍分配的。
有些服務器是非常常用的,為了使用方便,人們約定一些常用的服務器,都是用以下這些固定的端口號:
? ssh 服務器使用 22 端口
? ftp 服務器使用 21 端口
? telnet 服務器使用 23 端口
? http 服務器使用 80 端口
? https 服務器使用 443
在linux下我們可以通過 cat /etc/services 來查看知名端口號。在我們自己寫程序使用端口號時要避開這些知名端口號。
一個進程可以綁定多個端口號,一個端口號只能被一個進程綁定。
二、UDP協議
協議就是一種約定,協議本質就是通信雙方約定好的格式化字段,因此協議就是struct或者class定義的結構。操作系統中的UDP和TCP這些傳輸層協議及它們以下的協議在操作系統中就是純C的結構體,但是操作系統出于效率的考量,它選擇了在代碼里直接傳輸二進制的結構體對象,可以理解為沒有進行序列化與反序列化,也可以理解為直接以二進制的方式做的序列化和反序列化。添加報頭實際上就是定義了一個新的struct的結構體對象,然后把上一層的結構體對象與我們這一層的報頭合并起來。
2.1 UDP協議格式
UDP是如何解包,如何分用的呢?
UDP在解包時直接讀取前八個字節即它的報頭,剩下的部分就是有效載荷。而后通過16位的目的端口號分用的。
UDP是如何保證報文完整性的?
固定的報頭長度+16位UDP長度(用于標識有效載荷和報頭長度),再通過UDP16位校驗和進行校驗,成功則向應用層交付報文,失敗就要丟棄掉。
我們注意到,在UDP 協議首部中有一個 16 位的最大長度,也就是說一個 UDP 能傳輸的數據最大長度是 64K (包含 UDP 首部)。然而 64K 在當今的互聯網環境下是一個非常小的數字,如果我們需要傳輸的數據超過 64K,就需要在應用層手動的分包多次發送,并在接收端手動拼裝。?
下面是在Linux中的UDP結構:?
struct udphdr
{__u16 source;__u16 dest;__u16 len;__u16 check;
};
?2.2?UDP的特點
? 無連接:知道對端的 IP 和端口號就直接進行傳輸,不需要建立連接。
? 不可靠:沒有確認機制,也沒有重傳機制。如果因為網絡故障該段無法發到對方,UDP 協議層也不會給應用層返回任何錯誤信息。
? 面向數據報:不能夠靈活的控制讀寫數據的次數和數量。應用層交給 UDP 多長的報文,UDP 原樣發送,既不會拆分也不會合并。
2.3 UDP的緩沖區
? UDP 沒有真正意義上的發送緩沖區,調用 sendto 會直接交給內核,由內核將數據傳給網絡層協議進行后續的傳輸動作。
? UDP 具有接收緩沖區。但是這個接收緩沖區不能保證收到的 UDP 報的順序和發送 UDP 報的順序一致;緩沖區滿了之后到達的 UDP 數據會被丟棄。
UDP 的 socket 既能讀也能寫,這個概念叫做 全雙工。
2.4 基于 UDP 的應用層協議
? NFS:網絡文件系統
? TFTP:簡單文件傳輸協議
? DHCP:動態主機配置協議
? BOOTP:啟動協議(用于無盤設備啟動)
? DNS:域名解析協議
? 自定義的基于UDP的應用層協議