和TCP协议不同的是,UDP协议不需要进行稳定的连接即可直接对数据进行收发,即面向非连接的。所以UDP的应用场景在音视频流传输、在线游戏以及网络聊天室等实时传输需求大的背景。因为不需要建立连接,UDP的网络编程模型就比TCP简单许多。
接收端 | 发送端 |
创建socket | 创建socket |
准备通信地址 | 准备通信地址 |
绑定 | —— |
接收请求 | 发送请求 |
响应请求 | 接收响应 |
关闭socket | 关闭socket |
从这个UDP的网络通信模型可以很直观地看到,TCP的通信双方是客户端和服务器,而UDP通信的双方只是发送端和接收端。下面来看具体实现操作:
首先来看一下接收端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc,const char* argv[])
{
//创建套接字
int svrfd=socket(AF_INET,SOCK_DGRAM,0);
if(svrfd<0)
{
perror("socket");
return -1;
}
//准备通信地址(自己)
struct sockaddr_in svr_addr={},cli_addr={};
svr_addr.sin_family=AF_INET;
svr_addr.sin_port=htons(8888);
svr_addr.sin_addr.s_addr=inet_addr("192.168.110.12");
socklen_t addrlen=sizeof(svr_addr);
//绑定地址与套接字
if(bind(svrfd,(struct sockaddr *)&svr_addr,addrlen))
{
perror("bind");
return -1;
}
char buf[4096];
size_t buf_size=sizeof(buf);
while(1)
{
//接收数据和对方的地址
size_t ret=recvfrom(svrfd,buf,buf_size,0,(struct sockaddr *)&cli_addr,&addrlen);
if(ret<=0||0==strcmp("quit",buf))
{
printf("网络异常,通信结束!\n");
close(svrfd);
return -1;
}
printf("from %s recv:%s bits:%lu\n",inet_ntoa(cli_addr.sin_addr),buf,ret);
//响应
sprintf(buf,":return:%s",inet_ntoa(cli_addr.sin_addr));
ret=sendto(svrfd,buf,strlen(buf)+1,0,(struct sockaddr *)&cli_addr,addrlen);
if(ret<=0)
{
printf("对方网络异常\n");
}
}
close(svrfd);
return 0;
}
再来看一下发送端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc,const char* argv[])
{
//创建套接字
int clifd=socket(AF_INET,SOCK_DGRAM,0);
if(clifd<0)
{
perror("socket");
return -1;
}
//准备通信地址(对方)
struct sockaddr_in svr_addr={};
svr_addr.sin_family=AF_INET;
svr_addr.sin_port=htons(8889);
svr_addr.sin_addr.s_addr=inet_addr("192.168.110.26");
socklen_t addrlen=sizeof(svr_addr);
char buf[4096];
size_t buf_size=sizeof(buf);
while(1)
{
//发送请求
printf(">>>>>");
scanf("%s",buf);
size_t ret=sendto(clifd,buf,strlen(buf)+1,0,(struct sockaddr *)&svr_addr,addrlen);
if(ret<=0||0==strcmp("quit",buf))
{
printf("对方网络异常\n");
close(clifd);
break;
}
//接收响应
ret=recvfrom(clifd,buf,buf_size,0,(struct sockaddr *)&svr_addr,&addrlen);
if(ret<=0)
{
printf("网络异常,通信结束!\n");
close(clifd);
return -1;
}
printf("from %s recv:%s bits:%lu\n",inet_ntoa(svr_addr.sin_addr),buf,ret);
}
close(clifd);
return 0;
}
下面我来进行一下测试:
由上图,图2中由发送端发送数据到接收端,接收端接收并打印数据,并添加“:return”响应返回给发送端,最后输入quit结束通信,由此完成UDP的网络服务通信。