UDP是一個簡單的面向數據報的運輸層協議:進程的每個輸出操作通常會產生一個UDP數據報,並組裝成一份待發送的IP數據報。這與面向流的協議不同,如TCP,應用程序產生的數據與真正發送的單個IP數據報並不存在直接的關聯。
相關的協議參考tcp/ip協議學習筆記(7)UDP用戶數據報協議
UDP輸入和輸出以及輕量級UDP涉及以下文件:
include/net/udplite.h 定義輕量級UDP專用的函數等
include/linux/udp.h 定義UDP傳輸控制塊等
net/ipv4/udp.c UDP協議的實現
net/ipv4/udplite.c 輕量級UDP的實現
net/core/sock.c 實現傳輸層通用的函數
net/ipv4/datagram.c 實現UDP的connect調用
net/ipv4/af_inet.c 網絡層和傳輸層接口
UDP的輸入與輸出
UDP函數之間調用關係比TCP簡單的多,和TCP一樣,sock結構中的sk_receive_queue成員是UDP的接收隊列,通常情況下,接收到UDP數據報會緩存到此,等待用戶進程的讀取。UDP接收到數據報後的處理要比TCP簡單的多,通過校驗的UDP數據報,根據類型做不同的處理後被添加到接收隊列。
UDP傳輸控制塊
struct udp_sock {
/* inet_sock has to be the first member */
struct inet_sock inet;
int pending; /* Any pending frames ? */
unsigned int corkflag; /* Cork is required */
__u16 encap_type; /* Is this an Encapsulation socket? */
/*
* Following member retains the information to create a UDP header
* when the socket is uncorked.
*/
__u16 len; /* total length of pending frames */
/*
* Fields specific to UDP-Lite.
*/
__u16 pcslen;
__u16 pcrlen;
/* indicator bits used by pcflag: */
#define UDPLITE_BIT 0x1 /* set by udplite proto init function */
#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */
#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */
__u8 pcflag; /* marks socket as UDP-Lite if > 0 */
__u8 unused[3];
/*
* For encapsulation sockets.
*/
int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
};
struct inet_sock inet
udp_sock由inet_sock結構擴展而來
int pending
發送狀態,其值只能是0或AF_INET,0表示數據已經從UDP套接口發送到IP層,可以繼續調用sendmsg()發送數據,AF_INET表示UDP正在處理調用sendmsg()的發送數據,不需要處理目的地址、路由等信息,直接處理UDP數據
unsigned int corkflag
0 有數據需要發送時,立即發送出去
非0 將UDP數據組成一個單一64KB的UDP數據報後將其發送出去,因此會有延遲
__u16 len
從UDP套接口發送數據到IP層時,標識待發送數據的長度
__u16pcslen
__u16 pcrlen
輕量級UDP,通過UDPLITE_SEND_CSCOV和UDPLITE_RECV_CSCOV選項設置,用於實現控制發送和接收校驗和的執行
0 表示對發送/接收的整個UDP-Lite數據包進行校驗
>>=8 表示對發送/接收的UDP-Lite包的前pcslen/pcrlen個字節進行校驗
其他值是非法的
UDP的狀態
UDP的傳輸是沒有狀態的,但事實上,UDP和RAW也借用了TCP的一些值:在一個套接口創建之初,其狀態是TCP_CLOSE,當UDP套接口調用connect()後,狀態改變爲TCP_ESTABLISHED,最後,關閉套接口時又置回TCP_CLOSE,RAW也一樣。
輕量級UDP
2.6.20版本的Linux支持UDP-Lite。UDP-Lite協議相對較新,與UDP協議類似,但更適應網絡差錯率較大而應用對輕微差錯不敏感的情況,例如實時視頻播放等。那麼UDP-Lite與傳統的UDP有什麼不同呢?傳統的UDP協議對其負載(Payload)作完整的校驗,如果其中的哪怕只有一位發生了變化,那麼整個數據包就有可能被丟棄,在某些情況下,丟掉一個這樣的包代價是非常大的,尤其當數據包比較大的時候。在UDP-Lite協議中,一個數據包到底需不需對其負載進行校驗,或者是校驗多少位都是由用戶控制的,
Linux對UDP-Lite協議的支持也是通過在原來的UDP協議的基礎上添加了一個setsockopt選項來實現控制發送/接收 Checksum Coverage的
int val = 20;
setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int));
int min = 20;
setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int));
創建一個輕量級UDP套接口很簡單
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);