和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的网络服务通信。