epoll 1
/*poll 在已连接的套接字中遍历epoll_wait 返回的都是活跃的套接字,所以减少了很多无效的套接字Poll模型 :每次调用 poll函数的时候。都需要把监听套接字与已连接套接字所感兴趣的事件数组 拷贝到内核。LT模式 :Write EPOLLOUT 事件高电平 writebuf内核有空闲空间,我们就说他处于高电平状态,也就是一直处于活跃状态。此时可能会产生busy waitting loop低电平 当writebuf内核没有空闲空间,我们就说他处于低电平状态,没有激活。Read EPOLLIN 事件xxxET模型 边缘触发在该模式下,一开始我们就关注EPOLLIN事件和EPOLLOUT事件 , 此时writbuf一直处于高电平,不会触发EPOLLOUT事件.而EPOLLIN可能会产生,因为开始Readbuf是空的,如果在 epoll_wait前,readbuf有数据了,那么就有unreadablr--->readable,也就是产生了EPOLLLIN事件,这也是为什么监听socket 能够接收到外来请求的原因。关注EPOLLIN 和 EPOLLOUT事件后,我们也没必要取消他们的关注,只有到断开他们的socketfd时 , 我们才需要取消。需要注意的是,在读写时,如果是读,一定要读到EAGAIN,写也是要写到EAGAINsocket从unreadable变为readable或从unwritable变为writable有些人说从readable变为unreadable或者writable变为unwritable时也会触发事件。我个人觉得第一种合理一点。*/#include <unistd.h>#include <sys/types.h>#include <fcntl.h>#include <sys/socket.h>#include <netnet/in.h>#include <arpa/inet.h>#include <signal.h>#include <sys/wait.h>#include <sys/epoll.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <vector.h>#include <algorithm>#include <iostream>typedef std::vector<struct epoll_event> EventList ;#define ERR_EXIT(m) \do\{\perror(m);\exit(EXIT_FAILURE);\}while(0);int main ( void ) {//防止进程由于客户端的关闭而使服务器进程退出signal(SIGPIPE ,SIG_IGN) ;//防止僵死进程的发生signal(SIGCHLD,SIG_IGN);//备胎描述符int idlefd = open("/dev/null",O_RDONLY | O_CLOEXEC) ;//监听描述符int listenfd ;if((listenfd =socket(PF_INET,SOCK_STRAM|SOCK_NONBLOCK|SOCK_CLOSEXEC,IPPROTO_TCP))<0){ERR_EXIT("socket");}struct sockaddr_in servaddr ;memset(&servaddr,0,sizeof(servaddr)) ;servaddr.sin_family = AF_INET;servaddr.sin_port = htons(5188);servaddr.sin_addr.s_addr = htonl(INADDR_ANY) ;int on =1 ;//socketfd 重用if(setsocketopt(listenfd,SOL_SOCKET,SO_REUSERADDR,&on,sizeof(n))<0){ERR_EXIT("setsocketopt");}if( bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) <0)ERR_EXIT("bind");if(listen(listen,SOMAXCONN) <0)ERR_EXIT("listen");std::vector<int> clients;int epollfd;// 函数返回一个epoll专用的描述符epfd,epfd引用了一个新的epoll机制例程(instance.)。epollfd = epoll_create1(EPOLL_CLOEXEC);//事件结构体struct epoll_event event ;event.data.fd = listenfd ; //关注listenfdevent.events = EPOLLIN ; // /* | EPOLLET*/; 默认是LT模型// 把lisenfd 添加到epollfd 中进行管理//如果是poll的话,就不用这样了,poll直接使用一个数组就行了/*函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;op:要进行的操作例如注册事件,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修 改、EPOLL_CTL_DEL 删除fd:关联的文件描述符;event:指向epoll_event的指针;如果调用成功返回0,不成功返回-171 - 78 就交给epollfd 内核帮我们做了,并且只有epoll_ctl才会拷贝到内核,一次拷贝就行了,以后就不用拷贝了,如果我们使用poll 那么每次循环都要拷贝到内核里面去,大大降低了效率*/epoll_ctl(epollfd , EPOLL_CTL_ADD,listenfd,&event);//事件列表,初始为16 个EventList events(16) ;struct sockaddr_in peeraddr ;socklen_t peerlen ;int connfd ;int nready ;while(1){/*函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)该函数用于轮询I/O事件的发生;参数:epfd:由epoll_create 生成的epoll专用的文件描述符;epoll_event:用于回传代处理事件的数组,要处理的事件都会存储在events里面了maxevents:每次能处理的事件数;timeout:等待I/O事件发生的超时值(单位我也不太清楚);-1相当于阻塞,0相当于非阻塞。一般用-1即可返回发生事件数。-1 表示等待到至少一个事件发生*/nready = epoll_wait(epollfd,&*events.begin(),static_cast<int>(events.size()), -1 );if( nready == -1){if(errno == EINTR)continue ;ERR_EXIT("epoll补充:综合编程 , 其他综合 ,
上一个:epoll2
下一个:面向对象编程和基于对象编程