高效IO多路复用:select与poll

📅 2026/7/10 13:56:41
高效IO多路复用:select与poll
select函数实现IO多路复用 服务器端#include myhead.h #define SER_IP 192.168.125.152 #define SER_PORT 7070 int main(int argc, const char *argv[]) { int sfdsocket(AF_INET,SOCK_STREAM,0); if(sfd-1) { perror(socket error); return -1; } printf(socket success sfd%d\n,sfd); int reuse1; if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,reuse,sizeof(reuse))-1) { perror(setsockopt error); return -1; } printf(reusse port success\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); if(bind(sfd,(struct sockaddr*)sin,sizeof(sin))-1) { perror(bind error); return -1; } printf(bind success\n); if(listen(sfd,128)-1) { perror(listen error); return -1; } printf(listen success\n); //定义一个事件的文件描述符集合 fd_set readfds; fd_set tempfds;//用来操作的集合 //初始化添加文件描述符到集合 FD_ZERO(readfds); FD_SET(0,readfds); FD_SET(sfd,readfds); struct sockaddr_in cin; socklen_t socklensizeof(cin); int newfd-1; //客户端信息结构体数组用文件描述符当做数组的下标 struct sockaddr_in cin_arr[1024]; int maxfdsfd;//max作为select第一个参数初始值为maxfd1 while(1) { tempfdsreadfds; int resselect(maxfd1,tempfds,NULL,NULL,NULL); if(res0) { printf(time out\n); return -1; }else if(res-1) { perror(select error); return -1; } //程序运行至此说明集合中有事件发生 //遍厉每一个文件描述符,如果事件发生后此文件描述符还存在就执行相应程序 for(int i0;imaxfd;i) { //如果i对应的文件描述符没有事件发生直接下一位 if(!FD_ISSET(i,tempfds)) { continue; } if(sfdi) { newfdaccept(sfd,(struct sockaddr*)cin,socklen); if(newfd-1) { perror(accept error); return -1; } printf([%s:%d]:newfd%d\n,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd); //此处创建了一个新的文件描述符需要更新maxfd maxfdmaxfdnewfd?maxfd:newfd; //将新创建的newfd添加到事件文件描述符集合 FD_SET(newfd,readfds); //将接收到的客户端信息结构体放进结构体数组中 cin_arr[newfd]cin; } else if(0i) { char buf[128]; fgets(buf,sizeof(buf),stdin); buf[(strlen(buf)-1)]0; printf(触发键盘输入事件\n); for(int i4;imaxfd;i) { send(i,buf,strlen(buf),0); } } else { char rbuf[128]; bzero(rbuf,sizeof(rbuf)); int lenrecv(newfd,rbuf,sizeof(rbuf),0); if(len0) { printf(客户端下线\n); close(i);//关闭当前客户端 //将当前的文件描述符从集合中删去 FD_CLR(i,readfds); //删去文件描述符同时候也要更新maxfd //从maxfd往前遍历如果遍历到一个文件存在就是当前最大值文件描述符 for(int imaxfd;isfd;i--) { if(FD_ISSET(i,readfds))//判断该文件描述符是否存在 { maxfdi; break;//直到最大立即退出循环 } } continue;//如果当前客户端退出直接执行下一次事件的函数 } printf([%s:%d]:%s\n,inet_ntoa(cin_arr[i].sin_addr),\ ntohs(cin_arr[i].sin_port),rbuf); for(int i4;imaxfd;i) { send(i,rbuf,strlen(rbuf),0); } } } } return 0; }poll函数实现IO多路复用 客户端#include myhead.h #define SER_IP 192.168.125.152 #define SER_PORT 7070 #define CLI_IP 192.168.125.152 #define CLI_PORT 8765 int main(int argc, const char *argv[]) { int cfdsocket(AF_INET,SOCK_STREAM,0); if(cfd-1) { perror(socket error); return -1; } printf(socket success cfd%d\n,cfd); int reuse1; if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,reuse,sizeof(reuse))-1) { perror(setsockopt error); return -1; } printf(reusse port success\n); struct sockaddr_in cin; cin.sin_familyAF_INET; cin.sin_porthtons(CLI_PORT); cin.sin_addr.s_addrinet_addr(CLI_IP); if(bind(cfd,(struct sockaddr*)cin,sizeof(cin))-1) { perror(bind error); return -1; } printf(bind success\n); struct sockaddr_in sin; sin.sin_familyAF_INET; sin.sin_porthtons(SER_PORT); sin.sin_addr.s_addrinet_addr(SER_IP); if(connect(cfd,(struct sockaddr*)sin,sizeof(sin))-1) { perror(connect error); return -1; } printf(connect success\n); //文件描述符信息结构体数组 struct pollfd pfds[2];//控制两个文件描述符事件 pfds[0].fd0; pfds[0].eventsPOLLIN; pfds[1].fdcfd; pfds[1].eventsPOLLIN; char wbuf[128]; while(1) { int respoll(pfds,2,-1);//事件的文件描述符地址数量阻塞 if(res0) { printf(time out\n); return -1; }else if(res-1) { perror(poll error); return -1; } //程序运行到这个地方已经说明有事件发生 if(pfds[0].reventsPOLLIN) { fgets(wbuf,sizeof(wbuf),stdin); wbuf[strlen(wbuf)-1]0; if(strcmp(wbuf,quit)0)break; send(cfd,wbuf,strlen(wbuf),0); } if(pfds[1].reventsPOLLIN) { bzero(wbuf,sizeof(wbuf)); recv(cfd,wbuf,sizeof(wbuf),0); printf(服务器端发送的消息:%s\n,wbuf); } } close(cfd); return 0; }