UDP

UDP

UDP 是User Datagram Protocol的簡稱, 中文名是用戶數據報協定,是OSI(Open System Interconnection,開放式系統互聯) 參考模型中一種無連線的傳輸層協定,提供面向事務的簡單不可靠信息傳送服務,IETF RFC 768是UDP的正式規範。UDP在IP報文的協定號是17。

UDP協定全稱是用戶數據報協定,在網路中它與TCP協定一樣用於處理數據包,是一種無連線的協定。在OSI模型中,在第四層——傳輸層,處於IP協定的上一層。UDP有不提供數據包分組、組裝和不能對數據包進行排序的缺點,也就是說,當報文傳送之後,是無法得知其是否安全完整到達的。UDP用來支持那些需要在計算機之間傳輸數據的網路套用。包括網路視頻會議系統在內的眾多的客戶/伺服器模式的網路套用都需要使用UDP協定。UDP協定從問世至今已經被使用了很多年,雖然其最初的光彩已經被一些類似協定所掩蓋,但是即使是在今天UDP仍然不失為一項非常實用和可行的網路傳輸層協定。

與所熟知的TCP(傳輸控制協定)協定一樣,UDP協定直接位於IP(網際協定)協定的頂層。根據OSI(開放系統互連)參考模型,UDP和TCP都屬於傳輸層協定。UDP協定的主要作用是將網路數據流量壓縮成數據包的形式。一個典型的數據包就是一個二進制數據的傳輸單位。每一個數據包的前8個位元組用來包含報頭信息,剩餘位元組則用來包含具體的傳輸數據。

基本介紹

  • 中文名:用戶數據報協定
  • 外文名:User Datagram Protocol
  • 特點:不可靠快速傳輸
  • 簡稱:UDP
協定,使用,報頭,功能,報文格式,分層封裝,分解操作,配置命令,特性,對比,套用,程式設計,編寫程式,程式內容,例子程式,運行程式,分組結構,

協定

UDP是OSI參考模型中一種無連線的傳輸層協定,它主要用於不要求分組順序到達的傳輸中,分組傳輸順序的檢查與排序由套用層完成,提供面向事務的簡單不可靠信息傳送服務。UDP 協定基本上是IP協定與上層協定的接口。UDP協定適用連線埠分別運行在同一台設備上的多個應用程式
UDP提供了無連線通信,且不對傳送數據包進行可靠性保證,適合於一次傳輸少量數據,UDP傳輸的可靠性由套用層負責。常用的UDP連線埠號有:
套用協定 連線埠號
DNS 53
TFTP 69
SNMP 161
UDP報文沒有可靠性保證、順序保證和流量控制欄位等,可靠性較差。但是正因為UDP協定的控制選項較少,在數據傳輸過程中延遲小、數據傳輸效率高,適合對可靠性要求不高的應用程式,或者可以保障可靠性的應用程式,如DNS、TFTP、SNMP等。
UDP在IP報文中的位置如圖所示。
UDP

使用

在選擇使用協定的時候,選擇UDP必須要謹慎。在網路質量令人十分不滿意的環境下,UDP協定數據包丟失會比較嚴重。但是由於UDP的特性:它不屬於連線型協定,因而具有資源消耗小,處理速度快的優點,所以通常音頻、視頻和普通數據在傳送時使用UDP較多,因為它們即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。比如我們聊天用的ICQ和QQ就是使用的UDP協定。

報頭

UDP報頭由4個域組成,其中每個域各占用2個位元組,具體如下:1、源連線埠號。
UDPUDP
2、目標連線埠號。
3、數據報長度。
4、校驗值。
UDP協定使用連線埠號為不同的套用保留其各自的數據傳輸通道。UDP和TCP協定正是採用這一機制實現對同一時刻內多項套用同時傳送和接收數據的支持。數據傳送一方(可以是客戶端或伺服器端)將UDP數據包通過源連線埠傳送出去,而數據接收一方則通過目標連線埠接收數據。有的網路套用只能使用預先為其預留或註冊的靜態連線埠;而另外一些網路套用則可以使用未被註冊的動態連線埠。因為UDP報頭使用兩個位元組存放連線埠號,所以連線埠號的有效範圍是從0到65535。一般來說,大於49151的連線埠號都代表動態連線埠。
數據報的長度是指包括報頭和數據部分在內的總位元組數。因為報頭的長度是固定的,所以該域主要被用來計算可變長度的數據部分(又稱為數據負載)。數據報的最大長度根據操作環境的不同而各異。從理論上說,包含報頭在內的數據報的最大長度為65535位元組。不過,一些實際套用往往會限制數據報的大小,有時會降低到8192位元組。
UDP協定使用報頭中的校驗值來保證數據的安全。校驗值首先在數據傳送方通過特殊的算法計算得出,在傳遞到接收方之後,還需要再重新計算。如果某個數據報在傳輸過程中被第三方篡改或者由於線路噪音等原因受到損壞,傳送和接收方的校驗計算值將不會相符,由此UDP協定可以檢測是否出錯。這與TCP協定是不同的,後者要求必須具有校驗值。
許多鏈路層協定都提供錯誤檢查,包括流行的乙太網協定,也許你想知道為什麼UDP也要提供檢查和校驗。其原因是鏈路層以下的協定在源端和終端之間的某些通道可能不提供錯誤檢測。雖然UDP提供有錯誤檢測,但檢測到錯誤時,UDP不做錯誤校正,只是簡單地把損壞的訊息段扔掉,或者給應用程式提供警告信息。
UDP Helper是實現對指定UDP連線埠廣播報文的中繼轉發,即將指定UDP連線埠的廣播報文轉換為單播報文傳送給指定的伺服器,起到中繼的作用。

功能

為了在給定的主機上能識別多個目的地址,同時允許多個應用程式在同一台主機上工作並能獨立地進行數據包的傳送和接收,設計用戶數據報協定UDP。
使用UDP協定包括:TFTPSNMP、NFS、DNS、BOOTP
UDP使用底層的網際網路協定來傳送報文,同IP一樣提供不可靠的無連線數據包傳輸服務。它不提供報文到達確認、排序、及流量控制等功能。

報文格式

每個UDP報文分UDP報頭和UDP數據區兩部分。報頭由四個16位長(8位元組)欄位組成,分別說明該報文的源連線埠、目的連線埠、報文長度以及校驗值。

分層封裝

在TCP/IP協定層次模型中,UDP位於IP層之上。應用程式訪問UDP層然後使用IP層傳送數據報。IP層的報頭指明了源主機和目的主機地址,而UDP層的報頭指明了主機上的源連線埠和目的連線埠。

分解操作

UDP的復用、分解與連線埠
UDP軟體應用程式之間的復用與分解都要通過連線埠機制來實現。每個應用程式在傳送數據報之前必須與作業系統協商以獲得協定連線埠和相應的連線埠號。
UDP分解操作:從IP層接收了數據報之後,根據UDP的目的連線埠號進行分解操作。
UDP連線埠號指定有兩種方式:由管理機構指定連線埠和動態綁定的方式。

配置命令

1.1.1 display udp-helper server
【命令】
display udp-helper server[interfaceinterface-type interface-number]
【視圖】
任意視圖
【預設級別】
2:系統級
【參數】
interfaceinterface-type interface-number:顯示指定接口的UDP中繼轉發相關信息。interface-type interface-number為接口類型和接口編號。
【描述】
display udp-helper server命令用來顯示UDP中繼轉發的相關信息。
如果不選擇參數,則顯示所有接口的UDP中繼轉發相關信息。
【舉例】
# 顯示VLAN接口1的UDP中繼轉發相關信息。
<Sysname> display udp-helper server interface vlan-interface 1
Interface name Server address Packets sent
Vlan-interface1 192.1.1.2 0
以上顯示信息表示VLAN接口1對應的目的伺服器的IP位址為192.1.1.2,中繼轉發到該目的伺服器的報文數為0。
1.1.2 reset udp-helper packet
【命令】
reset udp-helper packet
【視圖】
用戶視圖
【預設級別】
2:系統級
【參數】
【描述】
reset udp-helper packet命令用來清除UDP中繼轉發的報文統計數目。
【舉例】
# 清除UDP中繼轉發的報文統計數目。
<Sysname> reset udp-helper packet
1.1.3 udp-helper enable
【命令】
udp-helper enable
undo udp-helper enable
【視圖】
系統視圖
【預設級別】
2:系統級
【參數】
【描述】
udp-helper enable命令用來使能UDP Helper功能,設備會將指定UDP連線埠的廣播報文轉換為單播報文傳送給指定的目的伺服器,起到中繼的作用。undo udp-helper enable命令用來關閉UDP Helper功能。
預設情況下,UDP Helper功能處於關閉狀態。
【舉例】
# 使能UDP Helper功能。
<Sysname> system-view
[Sysname] udp-helper enable
1.1.4 udp-helper port
【命令】
udp-helper port{port-number|dns|netbios-ds|netbios-ns|tacacs|tftp|time}
undo udp-helper port{port-number|dns|netbios-ds|netbios-ns|tacacs|tftp|time}
【視圖】
系統視圖
【預設級別】
2:系統級
【參數】
port-number:需要中繼轉發的UDP連線埠號,取值範圍為1~65535(不支持67和68)。
dns:對DNS的數據報文進行中繼轉發,對應的UDP連線埠號為53。
netbios-ds:對NetBIOS數據報服務的數據報文進行中繼轉發,對應的UDP連線埠號為138。
netbios-ns:對NetBIOS名字服務的數據報文進行中繼轉發,對應的UDP連線埠號為137。
tacacs:對終端訪問控制器訪問控制系統的數據報文進行中繼轉發,對應的UDP連線埠號為49。
tftp:對簡單檔案傳輸協定的數據報文進行中繼轉發,對應的UDP連線埠號為69。
time:對時間服務的數據報文進行中繼轉發,對應的UDP連線埠號為37。
【描述】
udp-helper port命令用來配置需要中繼轉發的UDP連線埠。undo udp-helper port命令用來取消對需要中繼轉發的UDP連線埠的配置。
預設情況下,沒有配置中繼轉發的UDP連線埠。
關閉UDP Helper功能後,所有已配置的UDP連線埠都被取消。
【舉例】
# 配置對目的UDP連線埠號為100的廣播報文進行中繼轉發。
<Sysname> system-view
[Sysname] udp-helper port 100
1.1.5 udp-helper server
【命令】
udp-helper serverip-address
undo udp-helper server[ip-address]
【視圖】
三層乙太網接口視圖/VLAN接口視圖
【預設級別】
2:系統級
【參數】
ip-address:目的伺服器的IP位址,為點分十進制形式。
【描述】
udp-helper server命令用來配置中繼轉發的目的伺服器。undo udp-helper server命令用來刪除中繼轉發的目的伺服器。
預設情況下,沒有配置中繼轉發的目的伺服器。
目前,一個接口上最多可以配置20箇中繼轉發的目的伺服器。
需要注意的是,undo udp-helper server命令後不加參數時,將會刪除該接口下配置的所有目的伺服器。
相關配置可參考命令display udp-helper server

特性

(1) UDP是一個無連線協定,傳輸數據之前源端和終端不建立連線,當它想傳送時就簡單地去抓取來自應用程式的數據,並儘可能快地把它扔到網路上。在傳送端,UDP傳送數據的速度僅僅是受應用程式生成數據的速度、計算機的能力和傳輸頻寬的限制;在接收端,UDP把每個訊息段放在佇列中,應用程式每次從佇列中讀一個訊息段。
UDPUDP
(2) 由於傳輸數據不建立連線,因此也就不需要維護連線狀態,包括收髮狀態等,因此一台服務機可同時向多個客戶機傳輸相同的訊息。
(3) UDP信息包的標題很短,只有8個位元組,相對於TCP的20個位元組信息包的額外開銷很小。
(4) 吞吐量不受擁擠控制算法的調節,只受套用軟體生成數據的速率、傳輸頻寬、源端和終端主機性能的限制。
(5)UDP使用盡最大努力交付,即不保證可靠交付,因此主機不需要維持複雜的連結狀態表(這裡面有許多參數)。
(6)UDP是面向報文的。傳送方的UDP對應用程式交下來的報文,在添加首部後就向下交付給IP層。既不拆分,也不合併,而是保留這些報文的邊界,因此,應用程式需要選擇合適的報文大小。
雖然UDP是一個不可靠的協定,但它是分發信息的一個理想協定。例如,在螢幕上報告股票市場、在螢幕上顯示航空信息等等。UDP也用在路由信息協定RIP(Routing Information Protocol)中修改路由表。在這些套用場合下,如果有一個訊息丟失,在幾秒之後另一個新的訊息就會替換它。UDP廣泛用在多媒體套用中,例如,Progressive Networks公司開發的RealAudio軟體,它是在網際網路上把預先錄製的或者現場音樂實時傳送給客戶機的一種軟體,該軟體使用的RealAudio audio-on-demand protocol協定就是運行在UDP之上的協定,大多數網際網路電話軟體產品也都運行在UDP之上。

對比

UDP和TCP協定的主要區別是兩者在如何實現信息的可靠傳遞方面不同。TCP協定中包含了專門的傳遞保證機制,當數據接收方收到傳送方傳來的信息時,會自動向傳送方發出確認訊息;傳送方只有在接收到該確認訊息之後才繼續傳送其它信息,否則將一直等待直到收到確認信息為止。與TCP不同,UDP協定並不提供數據傳送的保證機制。如果在從傳送方到接收方的傳遞過程中出現數據報的丟失,協定本身並不能做出任何檢測或提示。因此,通常人們把UDP協定稱為不可靠的傳輸協定
相對於TCP協定,UDP協定的另外一個不同之處在於如何接收突發性的多個數據報。不同於TCP,UDP並不能確保數據的傳送和接收順序。例如,一個位於客戶端的應用程式向伺服器發出了以下4個數據報
D1
D22
D333
D4444
但是UDP有可能按照以下順序將所接收的數據提交到服務端的套用:
D333
D1
D4444
D22
事實上,UDP協定的這種亂序性基本上很少出現,通常只會在網路非常擁擠的情況下才有可能發生。

套用

既然UDP是一種不可靠的網路協定,那么還有什麼使用價值或必要呢?其實不然,在有些情況下UDP協定可能會變得非常有用。因為UDP具有TCP所望塵莫及的速度優勢。雖然TCP協定中植入了各種安全保障功能,但是在實際執行的過程中會占用大量的系統開銷,無疑使速度受到嚴重的影響。反觀UDP由於排除了信息可靠傳遞機制,將安全和排序等功能移交給上層套用來完成,極大降低了執行時間,使速度得到了保證。
關於UDP協定的最早規範是RFC768,1980年發布。儘管時間已經很長,但是UDP協定仍然繼續在主流套用中發揮著作用。包括視頻電話會議系統在內的許多套用都證明了UDP協定的存在價值。因為相對於可靠性來說,這些套用更加注重實際性能,所以為了獲得更好的使用效果(例如,更高的畫面幀刷新速率)往往可以犧牲一定的可靠性(例如,畫面質量)。這就是UDP和TCP兩種協定的權衡之處。根據不同的環境和特點,兩種傳輸協定都將在今後的網路世界中發揮更加重要的作用。

程式設計

UDP Server程式

編寫程式

(1)使用socket()來建立一個UDP socket,第二個參數為SOCK_DGRAM。
(2)初始化sockaddr_in結構的變數,並賦值。sockaddr_in結構定義:
struct sockaddr_in {
uint8_t sin_len ;
sa_family_t sin_family;
in_port_t sin_port ;
structin_addrsin_addr;
char sin_zero[8];
};
這裡使用“8888”作為服務程式的連線埠,使用“INADDR_ANY”作為綁定的IP位址即任何主機上的地址。
(3)使用bind()把上面的socket和定義的IP位址和連線埠綁定。這裡檢查bind()是否執行成功,如果有錯誤就退出。這樣可以防止服務程式重複運行的問題。
(4)進入無限循環程式,使用recvfrom()進入等待狀態,直到接收到客戶程式傳送的數據,就處理收到的數據,並向客戶程式傳送反饋。這裡是直接把收到的數據發回給客戶程式。

程式內容

#include<sys/socket.h>#include<unistd.h>#include<string.h>#include<stdio.h>#include<arpa/inet.h>#include<stdlib.h>#defineMAXLINE80#defineSERV_PORT8888voiddo_echo(intsockfd,structsockaddr*pcliaddr,socklen_tclilen){intn;socklen_tlen;charmesg[MAXLINE];for(;;){len=clilen;/*waitingforreceivedata*/n=recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len);/*sentdatabacktoclient*/sendto(sockfd,mesg,n,0,pcliaddr,len);}}intmain(intargc,char*argv[]){intsockfd;structsockaddr_inservaddr,cliaddr;sockfd=socket(AF_INET,SOCK_DGRAM,0);/*createasocket*//*initservaddr*/bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_addr.s_addr=htonl(INADDR_ANY);servaddr.sin_port=htons(SERV_PORT);/*bindaddressandporttosocket*/if(bind(sockfd,(structsockaddr*)&servaddr,sizeof(servaddr))==-1){perror("binderror");exit(1);}do_echo(sockfd,(structsockaddr*)&cliaddr,sizeof(cliaddr));return0;}
UDP Client程式
1、編寫UDP Client程式的步驟
(1)初始化sockaddr_in結構的變數,並賦值。這裡使用“8888”作為連線的服務程式的連線埠,從命令行參數讀取IP位址,並且判斷IP位址是否符合要求。
(2)使用socket()來建立一個UDP socket,第二個參數為SOCK_DGRAM。
(3)使用connect()來建立與服務程式的連線。與TCP協定不同,UDP的connect()並沒有與服務程式三次握手。上面說了UDP是非連線的,實際上也可以是連線的。使用連線的UDP,kernel可以直接返回錯誤信息給用戶程式,從而避免由於沒有接收到數據而導致調用recvfrom()一直等待下去,看上去好像客戶程式沒有反應一樣。
(4)向服務程式傳送數據,因為使用連線的UDP,所以使用write()來替代sendto()。這裡的數據直接從標準輸入讀取用戶輸入。
(5)接收服務程式發回的數據,同樣使用read()來替代recvfrom()。
(6)處理接收到的數據,這裡是直接輸出到標準輸出上。
udpclient.c程式內容
#include<sys/socket.h>#include<unistd.h>#include<string.h>#include<stdio.h>#include<arpa/inet.h>#include<stdlib.h>#defineMAXLINE80#defineSERV_PORT8888voiddo_cli(FILE*fp,intsockfd,structsockaddr*pservaddr,socklen_tservlen){intn;charsendline[MAXLINE],recvline[MAXLINE+1];/*connecttoserver*/if(connect(sockfd,(structsockaddr*)pservaddr,servlen)==-1){perror("connecterror");exit(1);}while(fgets(sendline,MAXLINE,fp)!=NULL){/*readalineandsendtoserver*/write(sockfd,sendline,strlen(sendline));/*receivedatafromserver*/n=read(sockfd,recvline,MAXLINE);if(n==-1){perror("readerror");exit(1);}recvline[n]=0;/*terminatestring*/fputs(recvline,stdout);}}intmain(intargc,char**argv){intsockfd;structsockaddr_inservaddr;/*checkargs*/if(argc!=2){printf("usage:udpclient\n");exit(1);}/*initservaddr*/bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(SERV_PORT);if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr)<=0){printf("[%s]isnotavalidIPaddress\n",argv[1]);exit(1);}sockfd=socket(AF_INET,SOCK_DGRAM,0);do_cli(stdin,sockfd,(structsockaddr*)&servaddr,sizeof(servaddr));return0;}

例子程式

1、編譯例子程式
使用如下命令來編譯例子程式:
gcc -Wall -o udpserv udpserv.c
gcc -Wall -o udpclient udpclient.c
編譯完成生成了udpserv和udpclient兩個可執行程式。
2、運行UDP Server程式
執行./udpserv &命令來啟動服務程式。我們可以使用netstat -ln命令來觀察服務程式綁定的IP位址和連線埠,部分輸出信息如下:
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:32768 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN
tcp 0 0127.0.0.1:631 0.0.0.0:* LISTEN
udp 0 0 0.0.0.0:32768 0.0.0.0:*
udp 0 0 0.0.0.0:8888 0.0.0.0:*
udp 0 0 0.0.0.0:111 0.0.0.0:*
udp 0 0 0.0.0.0:882 0.0.0.0:*
可以看到udp處有“0.0.0.0:8888”的內容,說明服務程式已經正常運行,可以接收主機上任何IP位址且連線埠為8888的數據。
如果這時再執行./udpserv &命令,就會看到如下信息:
bind error: Address already in use
說明已經有一個服務程式在運行了。

運行程式

執行./udpclient 127.0.0.1命令來啟動客戶程式,使用127.0.0.1來連線服務程式,執行效果如下:
Hello,World!
Hello,World!
this is a test
this is a test
^d
輸入的數據都正確從服務程式返回了,按ctrl+d可以結束輸入,退出程式。
如果服務程式沒有啟動,而執行客戶程式,就會看到如下信息:
$ ./udpclient 127.0.0.1
test
read error: Connection refused
說明指定的IP位址和連線埠沒有服務程式綁定,客戶程式就退出了。這就是使用connect()的好處,注意,這裡錯誤信息是在向服務程式傳送數據後收到的,而不是在調用connect()時。如果使用tcpdump程式來抓包,會發現收到的是ICMP的錯誤信息。

分組結構

偏移位元組0123

相關詞條

熱門詞條

聯絡我們