当前位置:编程学习 > 网站相关 >>

epoll 1

/* 
 poll 在已连接的套接字中遍历 
 epoll_wait 返回的都是活跃的套接字,所以减少了很多无效的套接字 
 
 Poll模型 : 
 每次调用 poll函数的时候。都需要把监听套接字与已连接套接字所感兴趣的事件数组 拷贝到内核。 
 
 
 LT模式 : 
 Write  EPOLLOUT 事件 
    高电平 writebuf内核有空闲空间,我们就说他处于高电平状态,也就是一直处于活跃状态。此时可能会产生busy waitting loop 
    低电平 当writebuf内核没有空闲空间,我们就说他处于低电平状态,没有激活。 
Read EPOLLIN 事件 
    xxx 
 
 
 
 ET模型 边缘触发 
 在该模式下,一开始我们就关注EPOLLIN事件和EPOLLOUT事件 , 此时writbuf一直处于高电平,不会触发EPOLLOUT事件. 
        而EPOLLIN可能会产生,因为开始Readbuf是空的,如果在 epoll_wait前,readbuf有数据了,那么就有unreadablr--->readable, 
        也就是产生了EPOLLLIN事件,这也是为什么监听socket 能够接收到外来请求的原因。 
        关注EPOLLIN 和 EPOLLOUT事件后,我们也没必要取消他们的关注,只有到断开他们的socketfd时 , 我们才需要取消。 
 
需要注意的是,在读写时,如果是读,一定要读到EAGAIN,写也是要写到EAGAIN 
 socket从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 ; //关注listenfd 
    event.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,不成功返回-1  
 
71 - 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
补充:综合编程 , 其他综合 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,