UDP:用戶數(shù)據(jù)報(bào)
UDP是一個(gè)簡(jiǎn)單的面向數(shù)據(jù)報(bào)的運(yùn)輸層協(xié)議:進(jìn)程的每個(gè)輸出操作通常會(huì)產(chǎn)生一個(gè)UDP數(shù)據(jù)報(bào),并組裝成一份待發(fā)送的IP數(shù)據(jù)報(bào)。這與面向流的協(xié)議不同,如TCP,應(yīng)用程序產(chǎn)生的數(shù)據(jù)與真正發(fā)送的單個(gè)IP數(shù)據(jù)報(bào)并不存在直接的關(guān)聯(lián)。
UDP輸入和輸出以及輕量級(jí)UDP涉及以下文件:
include/net/udplite.h 定義輕量級(jí)UDP專用的函數(shù)等
include/linux/udp.h 定義UDP傳輸控制塊等
net/ipv4/udp.c UDP協(xié)議的實(shí)現(xiàn)
net/ipv4/udplite.c 輕量級(jí)UDP的實(shí)現(xiàn)
net/core/sock.c 實(shí)現(xiàn)傳輸層通用的函數(shù)
net/ipv4/datagram.c 實(shí)現(xiàn)UDP的connect調(diào)用
net/ipv4/af_inet.c 網(wǎng)絡(luò)層和傳輸層接口
UDP的輸入與輸出
UDP函數(shù)之間調(diào)用關(guān)系比TCP簡(jiǎn)單的多,和TCP一樣,sock結(jié)構(gòu)中的sk_receive_queue成員是UDP的接收隊(duì)列,通常情況下,接收到UDP數(shù)據(jù)報(bào)會(huì)緩存到此,等待用戶進(jìn)程的讀取。UDP接收到數(shù)據(jù)報(bào)后的處理要比TCP簡(jiǎn)單的多,通過校驗(yàn)的UDP數(shù)據(jù)報(bào),根據(jù)類型做不同的處理后被添加到接收隊(duì)列。
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結(jié)構(gòu)擴(kuò)展而來
int pending
發(fā)送狀態(tài),其值只能是0或AF_INET,0表示數(shù)據(jù)已經(jīng)從UDP套接口發(fā)送到IP層,可以繼續(xù)調(diào)用sendmsg()發(fā)送數(shù)據(jù),AF_INET表示UDP正在處理調(diào)用sendmsg()的發(fā)送數(shù)據(jù),不需要處理目的地址、路由等信息,直接處理UDP數(shù)據(jù)
unsigned int corkflag
0 有數(shù)據(jù)需要發(fā)送時(shí),立即發(fā)送出去
非0 將UDP數(shù)據(jù)組成一個(gè)單一64KB的UDP數(shù)據(jù)報(bào)后將其發(fā)送出去,因此會(huì)有延遲
__u16 len
從UDP套接口發(fā)送數(shù)據(jù)到IP層時(shí),標(biāo)識(shí)待發(fā)送數(shù)據(jù)的長(zhǎng)度
__u16pcslen
__u16 pcrlen
輕量級(jí)UDP,通過UDPLITE_SEND_CSCOV和UDPLITE_RECV_CSCOV選項(xiàng)設(shè)置,用于實(shí)現(xiàn)控制發(fā)送和接收校驗(yàn)和的執(zhí)行
0 表示對(duì)發(fā)送/接收的整個(gè)UDP-Lite數(shù)據(jù)包進(jìn)行校驗(yàn)
>>=8 表示對(duì)發(fā)送/接收的UDP-Lite包的前pcslen/pcrlen個(gè)字節(jié)進(jìn)行校驗(yàn)
其他值是非法的
UDP的狀態(tài)
UDP的傳輸是沒有狀態(tài)的,但事實(shí)上,UDP和RAW也借用了TCP的一些值:在一個(gè)套接口創(chuàng)建之初,其狀態(tài)是TCP_CLOSE,當(dāng)UDP套接口調(diào)用connect()后,狀態(tài)改變?yōu)門CP_ESTABLISHED,***,關(guān)閉套接口時(shí)又置回TCP_CLOSE,RAW也一樣。
輕量級(jí)UDP
2.6.20版本的Linux支持UDP-Lite。UDP-Lite協(xié)議相對(duì)較新,與UDP協(xié)議類似,但更適應(yīng)網(wǎng)絡(luò)差錯(cuò)率較大而應(yīng)用對(duì)輕微差錯(cuò)不敏感的情況,例如實(shí)時(shí)視頻播放等。那么UDP-Lite與傳統(tǒng)的UDP有什么不同呢?傳統(tǒng)的UDP協(xié)議對(duì)其負(fù)載(Payload)作完整的校驗(yàn),如果其中的哪怕只有一位發(fā)生了變化,那么整個(gè)數(shù)據(jù)包就有可能被丟棄,在某些情況下,丟掉一個(gè)這樣的包代價(jià)是非常大的,尤其當(dāng)數(shù)據(jù)包比較大的時(shí)候。在UDP-Lite協(xié)議中,一個(gè)數(shù)據(jù)包到底需不需對(duì)其負(fù)載進(jìn)行校驗(yàn),或者是校驗(yàn)多少位都是由用戶控制的,
Linux對(duì)UDP-Lite協(xié)議的支持也是通過在原來的UDP協(xié)議的基礎(chǔ)上添加了一個(gè)setsockopt選項(xiàng)來實(shí)現(xiàn)控制發(fā)送/接收 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));
創(chuàng)建一個(gè)輕量級(jí)UDP套接口很簡(jiǎn)單
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);