UDP的首部格式
- 源端口號(Source Port)
表示發送端端口號,字段長16位.該字段是可選項,有時可能不會設置源端口號,沒有端口號的時候該字段的只設置爲0,可用於不需要返回的通信中
- 目標端口號(Distination Port)
表示接收端端口號,字段長度爲16位
- 包長度
該字段保存了UDP首部的長度跟數據的長度之和,單位爲字節 - 校驗和
校驗和是爲了提供可靠的UDP首部和數據而設計
- 其中用戶數據報UDP有兩個字段:數據字段和首部字段
- 首部字段有8個字節,由4個字段組成,每個字段都是2個字節
- 注意
在計算校驗和時,臨時把 “僞首部” 和UDP用戶數據報連接在一起,僞首部僅僅時爲了計算校驗和
- 那麼校驗和計算中計算UDP僞首部的原因是什麼呢?
TCP/IP中識別一個進行通信的應用需要5大元素,他們分別是源IP地址、目標IP地址、源端口、目標端口、協議號。然而在UDP首部中只包含了他們當中的兩項(源端口和目標端口),餘下的3項都包含在IP首部中,假如其他三項遭到破壞的話,可能會導致對端收不到正確的包.因此,在了校驗和的計算中引入了僞首部的概念,用來提供可靠的通信傳輸
UDP的主要特點
-
1.UDP是無連接的,發送數據之前不需要建立連接,因此減少了開銷和發送數據之前的時延
-
2UDP使用盡最大努力交付,既不保證可靠交付,因此主機不需要維護複雜的連接狀態表
-
3.UDP是面向報文的,UDP對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界.UDP一次交付一個完整的報文
-
4.UDP沒有擁塞控制,因此網絡出現擁塞不會使源主機的發送速率降低,這對某些實時應用很重要的,很是個多媒體通信的要求
-
5.UDP支持一對一,一對多,多對一和多對多的交互通信
-
6.UDP的首部開銷小,只有8個字節,比TCP的20個自己的首部要短
-
UDP的傳輸的大致過程(簡略圖,只是爲了敘述方便)
-
用戶A給用戶B發送數據的時候,UDP對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界.UDP一次交付一個完整的報文給網絡層
-
而在接收端的用戶B在傳輸層拿到UDP報文之後,去掉UDP首部字段後原封不動的將UDP用戶數據報的數據部分交付給應用層一次交付一個完成的報文
UDP應用場景
- 包總量較少的通信(DNS\SNMP)
- 視頻、音頻等多媒體通信(即時通信)
- 限定於LAN等特定網絡中的應用通信
- 廣播通信(廣播、多播)
UDP編程(回顯服務器的實現)
UDP版本的服務器的編寫
- 縮影版
socket();
bind();
while(true){
recvfrom();
sendto();
}
close();
- 整體實現版本
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(){
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0){
perror("socket!");
return 1;
}
//準備工作
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(9090);
addr.sin_addr.s_addr=inet_addr("0.0.0.0");
int ret=bind(sock,(sockaddr*)& addr,sizeof(addr));
if(ret<0){
perror("bind!");
return 1;
}
printf("server is OK!\n");
while(true){
sockaddr_in peer;
char buf[1024]={0};
socklen_t len=sizeof(peer);
ssize_t n=recvfrom(sock,buf,sizeof(buf)-1,0,(sockaddr*)& peer,&len);
if(n<0){
perror("recvfrom!");
continue;
}
buf[n]='\0';
//根據請求計算響應,此處回顯服務器
//返回計算結果
n=sendto(sock,buf,strlen(buf),0,(sockaddr*)&peer,len);
if(n<0){
perror("sendto!");
continue;
}
printf("[%s:%d] res:%s\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port),buf);
}
close(sock);
return 0;
}
UDP版本的客戶端的實現
- 縮影版
sock();
while(true){
sendto();
recvfrom();
}
- 整體實現版本
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main(int argc,char* argv[]){
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0){
perror("socket!");
return 1;
}
//客戶端不需要綁定指定的固定的端口號
//用來和服務器進行交流,系統會自動分配
sockaddr_in server_addr;
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=inet_addr(argv[1]);
server_addr.sin_port=htons(9090);
while(true){
char buf[1024]={0};
printf("請輸入內容:");
scanf("%s",buf);
fflush(stdout);
sendto(sock,buf,strlen(buf),0,(sockaddr*)& server_addr,sizeof(server_addr));
char server_put[1024]={0};
recvfrom(sock,server_put,strlen(server_put)-1,0,NULL,NULL);
printf("server resp:%s\n",server_put);
}
return 0;
}
- 交互結果