一段时间内,轮询检测描述符上有没有用户感兴趣的事件产生。
描述符:socket、管道、键盘等
事件 :读、写、异常
FD_ZER(&fdset) fd_set – 清空整个集合,将fd_set 内的所有位置为0
FD_SET(fd,&fdest) fd ->fd_set – 向集合中添加描述符,将一个描述符添加到对应集合 fd_set
FD ISSET(fd,&fdset) – 检测描述符上是否有事件,检测描述符在集合中对应位置是否被置为1
fdset: 0000 0000
加入1,3,5
fdset: 0101 0100
select(&fdset) - 0001 0000
使用select 去检查服务器端的描述符 sockfd,c1,c2 …
在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。
思路:
先将描述符收集起来,再将数组中的描述符添加到集合中;
#include
#include
#include
#include
#include
#include
#include
#include
#include #define MAXFD 10void fds_init(int fds[])//对数组进行初始化
{for(int i=0; ifds[i] = -1;}
}void fds_add(int fd, int fds[])
{for(int i=0; iif(fds[i] == -1)//表示空闲,没有人使用{fds[i] = fd;break;}}
}int accept_client(int sockfd)
{struct sockaddr_in caddr;int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr*)&caddr,&len);return c;
}int socket_init();void fds_del(int fd,int fds[])//删除元素
{for(int i = 0; i < MAXFD; i++){if(fds[i] == fd){fds[i] = -1;break;}}
}int main()
{int fds[MAXFD];//记录所有的描述符fds_init(fds);int sockfd = socket_init();//监听套接字if( sockfd == -1){exit(0);}fds_add(sockfd,fds);//添加fd_set fdset;//集合收集描述符while( 1 ){FD_ZERO(&fdset);int maxfd = -1;//利用该找出集合中最大的描述符for(int i=0; iif( fds[i] == -1 ){continue;}FD_SET(fds[i],&fdset);//将数组中有效的描述符添加到集合if( fds[i] > maxfd ){maxfd = fds[i];}}struct timeval tv = {5,0};int n = select(maxfd+1,&fdset,NULL,NULL,&tv);//阻塞if( n == -1 ){printf("select err\n");}else if( n == 0){printf("time out\n");}else{for(int i = 0; i < MAXFD ; i++){if(fds[i] == -1){continue;}if( FD_ISSET(fds[i],&fdset))//判断描述符上是否有数据{if( fds[i] == sockfd)//为监听套接字,accept{int c = accept_client(fds[i]);if(c != -1){fds_add(c,fds);//添加新接收的连接} }else//recv{char buff[128] = {0};int num = recv(fds[i],buff,127,0);if(num <= 0)//出错或对方关闭{close(fds[i]);//关闭fds_del(fds[i],fds);//移除}else{printf("recv:%s\n",buff);send(fds[i],"ok",2,0);}}}}}}
}int socket_init()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if( sockfd == -1){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if( res == -1){ printf("bind err\n");return -1;}res = listen(sockfd,5);if(res == -1){return -1;}return sockfd;
}
int num = recv(fds[i],buff,127,0);
还有一个ok
poll类似于select,但它相当于加强版的select,其支持的小事件类型要更多。可以接收更多的描述符,select默认为1024,poll的则是根据所给数组所能容纳的大小。
即,poll实现类型更多,能容纳的描述符更多。内核所实现的效率相同。
某个位置为1,则代表某一事件。
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include #define MAXFD 10int socket_init();
void fds_del(int fd, struct pollfd fds[]);
int accept_client(int sockfd)
{struct sockaddr_in caddr;int len = sizeof(caddr);int c = accept(sockfd,(struct sockaddr*)&caddr,&len);return c;
}void recv_data(int c, struct pollfd fds[])
{char buff[128] = {0};int n = recv(c,buff,1,0);if ( n <= 0 ){close(c);fds_del(c,fds);printf("client close\n");return;}printf("recv:%s\n",buff);send(c,"ok",2,0);
}
void fds_init(struct pollfd fds[])
{for(int i = 0; i < MAXFD; i++ ){fds[i].fd = -1;fds[i].events = 0;fds[i].revents = 0;}
}void fds_add(int fd, struct pollfd fds[])
{for( int i = 0; i < MAXFD; i++ ){if ( fds[i].fd == -1 ){fds[i].fd = fd;fds[i].events = POLLIN | POLLRDHUP;fds[i].revents = 0;break;}}
}void fds_del(int fd, struct pollfd fds[])
{for(int i = 0; i < MAXFD; i++ ){if ( fds[i].fd == fd){fds[i].fd = -1;fds[i].events = 0;fds[i].revents = 0;break;}}
}
int main()
{int sockfd = socket_init();if ( sockfd == -1 ){exit(0);}struct pollfd fds[MAXFD];fds_init(fds);fds_add(sockfd,fds);//sockfd -> fdswhile( 1 ){int n = poll(fds,MAXFD,5000);//阻塞if ( n == -1 ){printf("poll err\n");}else if ( n == 0 ){printf("time out\n");}else{for(int i = 0; i < MAXFD; i++ ){if( fds[i].fd == -1 ){continue;}/*if ( fds[i].revents & POLLRDHUP){printf("close --rdhup\n");close(fds[i].fd);fds_del(fds[i].fd,fds);continue;}*/if ( fds[i].revents & POLLIN ){if ( fds[i].fd == sockfd){int c = accept_client(sockfd);if ( c != -1 ){fds_add(c,fds);}}else{recv_data(fds[i].fd,fds);}}//if ( fds[i].revents & POLLOUT )//{//}}}}}int socket_init()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);if ( sockfd == -1 ){return -1;}struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_port = htons(6000);saddr.sin_addr.s_addr = inet_addr("127.0.0.1");int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));if ( res == -1 ){printf("bind err\n");return -1;}res = listen(sockfd,5);if ( res == -1 ){return -1;}return sockfd;
}
是Linux系统上特有的系统调用。
epoll 其实是由一组方法构成。
epoll_create() //在内核中创建内核事件表 -- 相当于容器 ,是一颗红黑树,RBR
epoll_ctl() //向表中添加,修改,移除
epoll_wait() //获取就绪描述符
上一篇:鲸鱼优化算法预测
下一篇:期货买卖的难点(期货的买卖理由)