udp 是一种无连接的传输协议, 全称User Datagram Protocol. 由于其无连接的特性, 放弃数据的可靠性, 换取更简单的交互逻辑, 更简单的数据结构和更高的传输性能. 即使udp协议不可靠, 应该说是传输层
的不可靠. 但通过应用层再次开发还是可以在一定程度上保证数据的可靠性.
upd的使用场景:
- 需要资源少, 在网络情况较好的内网, 或对丢包不敏感的应用
- 不需要一对一沟通, 建立连接, 而是可以广播的应用
- 需要处理速度快, 时延低, 可以容忍少数丢包, 但要求即便网络拥塞, 也毫不退缩, 一往无前的时候
- 需要多播, 应用层自己控制传输的地方: DHCP, VXLAN, QUIC
使用场景具体的例子:
- 网页或者APP的访问
- QUIC(Quick UDP Internet Connections, 快速Udp 互联网连接): 快速建立连接, 减少重传时延, 自适应拥塞控制
- 流媒体的协议
- 实时游戏
- IoT 物联网: 物联网通信协议Thread, 基于Udp协议
- 移动通信领域: GTP-U 协议, 基于Udp协议
udp 协议头

上图中有一个伪首部
并不是udp协议的一部分, 而是用于计算udp首部校验和时使用的. 而整个udp首部仅有8个字节, 可见udp协议是如此的简单.
下面看一个udp客户端和服务端的实例:
- 客户端
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define PORT 6023
#define ADDR "0.0.0.0"
int main(int argc, char *argv[]) {
int sock = -1, ret = 0;
struct sockaddr_in addrto;
const char *smsg = "The msg from udp client";
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
printf("socket error\n");
return -1;
}
addrto.sin_family = AF_INET;
addrto.sin_addr.s_addr = inet_addr(ADDR);
addrto.sin_port = htons(PORT);
while (1) {
ret = sendto(sock, smsg, strlen(smsg), 0, (struct sockaddr *)&addrto, sizeof(addrto));
if (ret < 0) {
printf("send error....\n");
} else {
printf("send msg: %s\n", smsg);
}
sleep(1);
}
return 0;
}
- 服务端
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define PORT 6023
int main() {
struct sockaddr_in addr, from;
int sock = -1, ret = 0;
int len = sizeof(struct sockaddr_in);
char smsg[100] = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
printf("socket error\n");
return -1;
}
if (bind(sock, (struct sockaddr *)&(addr), sizeof(addr)) == -1) {
printf("bind error...\n");
return -1;
}
while (1) {
ret = recvfrom(sock, smsg, sizeof(smsg) - 1, 0,
(struct sockaddr *)&from, (socklen_t *)&len);
if (ret <= 0) {
printf("read error....\n");
} else {
printf("recv msg: %s\n", smsg);
}
}
return 0;
}
- Makefile
all: cln svr
cln: cln.o
gcc -o $@ $^
svr: svr.o
gcc -o $@ $^
clean:
rm -f *.o cln svr
如果觉得有帮助, 可以扫描右边的微信打赏码支持一下.