關於UDP的特點和編程你瞭解嗎?

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編程接口總結

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;
}
  • 交互結果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章