UDP协议

298 阅读3分钟

UDP协议

UDP协议(User Datagram Protocol,用户数据报协议)是不可靠的传输层协议,UDP协议的重点内容有

  1. UDP协议的报头
  2. UDP套接字
  3. UDP协议的特点

UDP协议的报头

UDP协议的报头如下

image.png

  • 16位源端口号:指明了发送数据的进程
  • 16位目的端口号:指明了接受数据的进程,UDP协议根据16位目的端口号确定将数据交付给上层哪一个进程
  • 16位UDP长度:指的是16位UDP总长度,包括报头和有效载荷
  • 16位UDP检验和:数据接收端通过16位UDP校验和来判断数据是否发生损坏,校验和不通过则直接丢弃报文

单个UDP报文能够携带的最大有效载荷为65527字节,UDP报头采取的是定长报头,大小是8字节,UDP报文的总长度是16位,单个UDP报文可以携带的最大有效载荷即为65535-8=65527字节(实际上单个UDP报文可以携带的数据量是比较少的)。

UDP报头在系统中是位段结构

struct udp_header {
	int src_port : 16;
	int dst_port : 16;
	int total_length : 16;
	int check : 16;
};

UDP套接字

Linux中UDP相关的接口为sendto和recvfrom

#include<sys/types.h>
#include<sys/socket.h>
ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t addrlen);

使用UDP协议进行通信的流程

  1. 通过socket创建套接字
  2. 直接调用sendto发送数据
  3. 直接调用recvfrom接受数据
  4. 调用close关闭套接字

由于UDP协议是无连接的,在调用sendto时,即使填写的接受方地址不正确,sendto函数也会成功返回(只是数据在路由的过程中由于找不到接收方而被丢弃)

int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(3333);
addr.sin_addr.s_addr = inet_addr("123.123.123.123");
char msg[] = "hello world";
if (sendto(sock, msg, strlen(msg), 0, (const struct sockaddr *)&addr, sizeof(addr)) > 0) {
	printf("sendto函数调用成功\n");
}
close(sock);

UDP协议的特点

  1. 无连接

    UDP协议不需要像TCP协议一样,在双方通信前需要进行三次握手建立链接

  2. 不可靠

    若传输的数据丢失,UDP协议不会进行重传,且UDP协议没有确认应答机制,不能保证发送的数据一定可以被对方收到

  3. 面向数据报

    发送端一次必须发送一个完整的报文,接收端一次必须接受一个完整的报文

  4. 全双工

    UDP的socket即能读也能写,称为全双工

  5. 缓冲区

    UDP存在接收缓冲区,没有发送缓冲区,通过recvfrom读取到的数据是从UDP的接收缓冲区读取到的,UDP接收缓冲区中收到的报文不能保证有序 image.png

基于UDP协议的应用层协议

  • NFS协议:网络文件系统
  • DHCP协议:动态主机配置协议,用于给局域网中的主机自动分配ip地址
  • DNS协议:用于域名解析
  • TFTP协议:简单文件传输协议
  • BOOTP协议:无盘设备的启动