关于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;
}
  • 交互结果

在这里插入图片描述

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