UDP协议
UDP协议(User Datagram Protocol,用户数据报协议)是不可靠的传输层协议,UDP协议的重点内容有
- UDP协议的报头
- UDP套接字
- UDP协议的特点
UDP协议的报头
UDP协议的报头如下
- 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协议进行通信的流程
- 通过socket创建套接字
- 直接调用sendto发送数据
- 直接调用recvfrom接受数据
- 调用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协议的特点
-
无连接
UDP协议不需要像TCP协议一样,在双方通信前需要进行三次握手建立链接
-
不可靠
若传输的数据丢失,UDP协议不会进行重传,且UDP协议没有确认应答机制,不能保证发送的数据一定可以被对方收到
-
面向数据报
发送端一次必须发送一个完整的报文,接收端一次必须接受一个完整的报文
-
全双工
UDP的socket即能读也能写,称为全双工
-
缓冲区
UDP存在接收缓冲区,没有发送缓冲区,通过recvfrom读取到的数据是从UDP的接收缓冲区读取到的,UDP接收缓冲区中收到的报文不能保证有序
基于UDP协议的应用层协议
- NFS协议:网络文件系统
- DHCP协议:动态主机配置协议,用于给局域网中的主机自动分配ip地址
- DNS协议:用于域名解析
- TFTP协议:简单文件传输协议
- BOOTP协议:无盘设备的启动