UDP是无连接的,即发送数据之前不需要建立连接,它尽最大努力交付,即不保证可靠交付,在一些要求实时性的通信中多有用到如游戏,视频等,UDP是面向报文的,有别于tcp的一对一通信,udp支持一对一、一对多、多对一和多对多的交互通信等。
int socket(int domain, int type, int protocol);
功能:创建socket对象
type:SOCK_DGRAM 数据报协议 UDP
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定socket和通信地址
sockfd:socket描述符
addr:地址结构体指针,实际传递的是 sockaddr_un或者sockaddr_in 结构体指针,需要把它们统一转换为sockaddr*类型。具体sockaddr_in结构体在socket的本地通信博文中有提到,这里不再赘述。
UDP专属的数据发送接收函数:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:UDP协议发送数据
sockfd:socket描述符
buf:待发送数据内存首地址
len:待发送数据的字节数
flags:是否阻塞 一般写0阻塞即可
dest_addr:通信目标的地址
addrlen:地址结构体的字节数
返回值:成功发送的字节数,0表示通信关闭,-1表示出现错误
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
功能:UDP协议接收数据
sockfd:socket描述符
buf:存储接收数据的缓冲区内存首地址
len:缓冲区的字节数
flags:是否阻塞 一般写0阻塞即可
src_addr:用于存储发送者的地址
addrlen:既是输入,也是输出,既告诉函数当前src_addr结构体的字节数,同时也能实际接收到发送者的地址结构体字节数。
返回值:成功接收到的字节数,0表示通信关闭,-1表示出现错误。
基于UDP通信协议的网络通信编程模型:
接收端 发送端
创建socket 创建socket
准备通信地址 准备通信地址
绑定 ...
接收请求 发送请求
响应请求 接收响应
关闭socket 关闭socket
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr* SP;
int main(int argc,const char* argv[])
{
// 创建socket
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(0 > sockfd)
{
perror("socket");
return EXIT_FAILURE;
}
// 准备本机通信地址
struct sockaddr_in srv_addr = {},cli_addr = {};
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(7788);
//这里的“xxx.xx.xx.xx”写本机的ip地址,可以用ifconfig命令查看,windows可以用ipconfig查看
srv_addr.sin_addr.s_addr = inet_addr("xxx.xx.xx.xx");
socklen_t addrlen = sizeof(srv_addr);
// 绑定
if(bind(sockfd,(SP)&srv_addr,addrlen))
{
perror("bind");
return EXIT_FAILURE;
}
char buf[4096] = {};
size_t buf_size = sizeof(buf);
for(;;)
{
// 接收数据和对方的地址
int ret = recvfrom(sockfd,buf,buf_size,0,(SP)&cli_addr,&addrlen);
if(0 >= ret)
{
printf("网络异常,通信结束!");
close(sockfd);
return EXIT_FAILURE;
}
printf("from %s recv:[%s] bits:%d\n",
inet_ntoa(cli_addr.sin_addr),buf,ret);
// 返回响应
strcat(buf,"from udpS");
ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&cli_addr,addrlen);
if(0 >= ret)
{
printf("对方网络异常!\n");
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr* SP;
int main(int argc,const char* argv[])
{
// 创建socket
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(0 > sockfd)
{
perror("socket");
return EXIT_FAILURE;
}
// 准备服务器通信地址
struct sockaddr_in srv_addr = {};
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(7788);
srv_addr.sin_addr.s_addr = inet_addr("xx.xx.xxx.xxx");//这里写需要通信的ip地址
socklen_t addrlen = sizeof(srv_addr);
char buf[4096] = {};
size_t buf_size = sizeof(buf);
for(;;)
{
printf(">>>");
scanf("%s",buf);
if(0 == strcmp(buf,"quit"))
{
printf("结束通信!\n");
close(sockfd);
return EXIT_SUCCESS;
}
int ret = sendto(sockfd,buf,strlen(buf)+1,0,(SP)&srv_addr,addrlen);
if(0 >= ret)
{
printf("网络异常!\n");
close(sockfd);
return EXIT_FAILURE;
}
// 接收数据和对方的地址
ret = recvfrom(sockfd,buf,buf_size,0,(SP)&srv_addr,&addrlen);
if(0 >= ret)
{
printf("网络异常,通信结束!");
close(sockfd);
return EXIT_FAILURE;
}
printf("from %s recv:[%s] bits:%d\n",
inet_ntoa(srv_addr.sin_addr),buf,ret);
}
}