UDP(User Datagram Protocol)是一种无连接的传输层协议,位于OSI模型的第四层。与TCP不同,UDP不提供可靠性保证、流量控制或拥塞控制机制,但具有低延迟和高效率的特点。
UDP的主要特性
无连接性
UDP在通信前无需建立连接,直接发送数据报。这减少了握手和断连的开销,但无法保证数据包的顺序或完整性。
不可靠传输
UDP不提供确认、重传或错误恢复机制。若数据包丢失或损坏,协议本身不会主动处理,需由应用层解决。
低开销
UDP头部仅8字节(包含源端口、目标端口、长度和校验和),远小于TCP的20字节头部,减少了传输负担。
支持广播和多播
UDP能够向多个目标同时发送数据包(广播或多播),适用于实时音视频、在线游戏等场景。
UDP的典型应用场景
- 实时多媒体传输:如VoIP(语音通话)、视频会议(如Zoom部分使用UDP)。
- 在线游戏:对延迟敏感的场景优先选择UDP,例如FPS游戏。
- DNS查询:DNS协议默认使用UDP,快速解析域名。
- IoT设备通信:传感器数据上报等轻量级通信。
UDP与TCP的对比
| 特性 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接 | 面向连接 |
| 可靠性 | 不可靠 | 可靠(确认、重传) |
| 传输效率 | 高(低开销) | 较低(头部大) |
| 数据顺序 | 不保证 | 保证按序到达 |
| 适用场景 | 实时应用、广播 | 文件传输、网页浏览 |
UDP的编程函数
在UDP中我们用到的函数如下
服务器端:
UDP编程常用函数
socket()
创建套接字,指定协议族(如AF_INET)和套接字类型(SOCK_DGRAM)。
int socket(int domain, int type, int protocol);
bind()
将套接字绑定到本地IP地址和端口,通常用于服务器端。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sendto()
发送数据到指定的目标地址,适用于无连接的UDP通信。
cpp
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
recvfrom()
接收数据并获取发送方的地址信息,常用于服务器或客户端接收响应。
cpp
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
close()
关闭套接字释放资源。
cpp
int close(int sockfd);
UDP客户端
socket()
sendto()
recevfrom()
close()
使用socket()创建套接字,使用UDP协议时,选择的SOCK_DGRAM,使用sendto()发送资源,由于UDP时无连接的,每次都要发送数据都需要指定对端的地址,recbform()接收数据,每次都需要传给该方法的一个地址结构存放发送端的地址,recvform()可以接收所有客户端发送给当前应用程序的数据,并不能接收一个客户端的数据.
UDP服务器代码
cpp
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<arpa/inet.h>
#include<pthread.h>
int main(){
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(-1==sockfd)
{
exit(1);
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(9999);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int n=bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));
if(-1==n){
printf("bind arror");
exit(1);
}
while(1){
char buf[128]={0};
int len=sizeof(saddr);
int n=recvfrom(sockfd,buf,127,
0,(struct sockarr *)&saddr,&len);
sendto(sockfd,buf,sizeof(buf)-1,0,(struct sockarr*)&saddr,sizeof(saddr));
if(n<0){
break;
}
printf("%s",buf);
sendto(sockfd,"YES",3,0,(struct sockaddr *)&saddr,len);
}
close(sockfd);
}
UDP客户端代码
cpp
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(-1==sockfd)
{
exit(1);
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(9999);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
char buf[128]={0};
fgets(&buf,127,stdin);
int n=sendto(sockfd,buf,127,0,
(struct sockaddr *)&saddr,sizeof(saddr));
recvfrom(sockfd,buf , 127, 0,(struct sockaddr *)&saddr, sizeof(saddr));
printf("buff = %s\n", buf);
close(sockfd);
}