UDP socket 编程以及IO多路复用
一)什么是UDP
提供无连接,不可靠的信息传输服务,
该协议不对传输的数据包排序,不需要接收方应答确认信息
应用程序需自己构建发送数据的顺序和确认机制
与TCP协议相比具有速度优势
UDP通常用在资源消耗小,处理速度要求快的场合,如音频和视频的传输。
二)UDP socket 编程
服务器:
1.创建服务器套接字用于唯一标识服务器
int connfd = socket(AF_INET,SOCK_DGRAM,0);//SOCK_DGRAM:描述要创建的套接字类型为数据报套接字类型if(connfd < 0){perror("socket");return -1;}
struct sockaddr_in saddr;saddr.sin_family = SOCK_DGRAM;saddr.sin_port = htons(12345);saddr.sin_addr.s_addr = inet_addr("0.0.0.0");int ret = bind(connfd,(struct sockaddr *)&saddr,sizeof(saddr));if(ret < 0){perror("bind");return -1;}
struct sockaddr_in caddr;int clen = sizeof(caddr);char buf[56] = {0};if(recvfrom(connfd,buf,sizeof(buf),0,(struct sockaddr *)&caddr,&clen) < 0){perror("recvfrom");return -1;}printf("client->%s\n",buf);printf("已接收到客户端消息,成功与客户端建立连接!\n");
strcpy(buf,"I Love You");ret = sendto(connfd,buf,sizeof(buf),0,(struct sockaddr *)&caddr,sizeof(caddr));if(ret < 0){perror("sendto");return -1;}
客户端
1.创建套接字唯一标识客户端
int connfd = socket(AF_INET,SOCK_DGRAM,0);if(connfd < 0){perror("connfd");return -1;}struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(12345);saddr.sin_addr.s_addr = inet_addr("192.168.64.137");3.向服务器发送信息以及客户端的IP和端口号
char buf[56] = "xieting";int ret = sendto(connfd,buf,sizeof(buf),0,(struct sockaddr *)&saddr,sizeof(saddr));if(ret < 0){perror("sendto");return -1;}4.接收服务器的反馈消息
struct sockaddr_in oaddr;int olen = sizeof(oaddr);char back[56] = {0};ret = recvfrom(connfd,back,sizeof(buf),0,(struct sockaddr *)&oaddr,&olen);if(ret < 0){perror("recvfrom");return -1;}printf("server->%s\n",back);结果
xieting已接收到客户端消息,成功与客户端建立连接!server->I Love You二)IO多路复用
1.什么是IO多路复用 I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
2.IO多路复用的基本步骤 -
创建一个文件描述符集合 -
将要关注的文件描述符加入这个集合 -
调用select函数,将不活跃的描述符清除掉, -
循环遍历select后的描述符集合,判断关注的文件描述符是否还在集合里 -
若在,执行相应的操作 -
若不在,continue执行下一次判断
3.代码如下
服务器
/*===============================================================* 文件名称:server_TCP.c* 创 建 者:zhongyue* 创建日期:2020年08月03日================================================================*/int main(void){//1.创建一个套接字int listenfd = socket(AF_INET,SOCK_STREAM,0);if(listenfd < 0){perror("socket");return -1;}//2.绑定struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(12345);saddr.sin_addr.s_addr = inet_addr("0.0.0.0");int ret = bind(listenfd,(struct sockaddr *)&saddr,sizeof(saddr));if(ret < 0){perror("bind");return -1;}//3.设置监听套接字int backlog = 20;ret = listen(listenfd,backlog);if(ret < 0){perror("listen");return -1;}//4.创建描述符集合fd_set readfds,writefds;//创建描述符读集合和写集合FD_ZERO(&readfds);//清空描述符集合FD_ZERO(&writefds);//清空描述符集合FD_SET(listenfd,&readfds);//将监听套接字写入集合int maxfd = listenfd;//初始化最大文件描述符fd_set tmpfds = readfds;//定义一个中间变量记录最初的文件间描述符集合,因为readsfds一直在改变struct sockaddr_in caddr;int clen = sizeof(caddr);while(1){readfds = tmpfds;//readfds重新赋值int ret = select(maxfd+1,&readfds,NULL,NULL,NULL);//调用select函数清除不活跃的描述符if(ret < 0){perror("select");return -1;}for(int i=3;i<maxfd+1;i++){ //循环遍历描述符if(FD_ISSET(i,&readfds)){if(i == listenfd){ //如果套接字存在且是监听套接字,则调用accept连接客户端int connfd = accept(listenfd,(struct sockaddr *)&caddr,&clen);if(connfd < 0){perror("accept");return -1;}printf("客户端已连入!\n");printf("客户端的IP地址为:%s\n",inet_ntoa(caddr.sin_addr));printf("客户端的端口号为:%d\n",ntohs(caddr.sin_port));FD_SET(connfd,&tmpfds);//将连接套接字加入描述符集合maxfd = maxfd > connfd?maxfd:connfd;//更新最大描述符}else{ //如果是连接套接字,则处理数据的收发char buf[128] = {"xieting"};ret = read(i,buf,sizeof(buf));//接收客户端发来的数据if(ret < 0){perror("read");continue;}printf("%s\n",buf);if(ret == 0){ //如果客户端断开连接,清除这个连接套接字printf("客户端已断开!\n");printf("-------------\n");close(i);FD_CLR(i,&tmpfds);//更新最大描述符maxfd}write(i,buf,sizeof(buf));//向客户端反馈接收到的数据if(errno == EDESTADDRREQ){continue;}}}}}}
客户端
/*===============================================================* 文件名称:client.c* 创 建 者:zhongyue* 创建日期:2020年08月03日================================================================*/int main(void){//1.创建一个套接字int connfd = socket(AF_INET,SOCK_STREAM,0);if(connfd < 0){perror("fail to socket");return -1;}//2.连接服务器struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(12345);saddr.sin_addr.s_addr = inet_addr("192.168.64.137");int ret = connect(connfd,(struct sockaddr *)&saddr,sizeof(saddr));if(ret < 0){perror("connect");return -1;}printf("已连接服务器!\n");while(1){char buf[128] = "nice to meet you";ret = write(connfd,buf,sizeof(buf));if(ret < 0){perror("write");return -1;}sleep(1);read(connfd,buf,sizeof(buf));printf("%s\n",buf);}return 0;}
