epoll EPOLLLT模式和EPOLLET模式

Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!

Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!

下面的代码有注解

#include 
#include 
#include 
#include 
#include 
#include  //for bzero
#include 
#include 
#include 
 
using namespace std;
 
#define MAX_LINE 20
#define MAX_EVENTS 500
#define MAX_LISTENFD 5
 
int createAndListen()
{
    int on = 1;
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in servaddr;
    fcntl(listenfd, F_SETFL, O_NONBLOCK); //no-block io
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(11112);
    
    if(-1 == bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)))
    {
        cout << "bind error, errno:" << errno << endl; 
    }
 
    if(-1 == listen(listenfd, MAX_LISTENFD))
    {
        cout << "listen error, errno:" << errno << endl; 
    }
    return listenfd;
}
 
int main(int args, char** argv)
{
    struct epoll_event ev, events[MAX_EVENTS];
    int listenfd,connfd,sockfd;
    int readlength;
    char line[MAX_LINE];
    struct sockaddr_in cliaddr;
    socklen_t clilen = sizeof(struct sockaddr_in);
    int epollfd = epoll_create(1);
    if (epollfd < 0)
        cout << "epoll_create error, error:" << epollfd << endl;
    listenfd = createAndListen();
    ev.data.fd = listenfd;
    ev.events = EPOLLIN;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev);
 
    for(;;)
    {
        int fds = epoll_wait(epollfd, events, MAX_EVENTS, -1);   //在EPOLLET模式下,read(sockfd, line, N),如果N > 缓冲期数据真实大小,这里只会触发一次,EPOLLLT模式下不管IO是否阻塞都会多次触发
        if(fds == -1)
        {
            cout << "epoll_wait error, errno:" << errno << endl; 
            break;
        }
        else  {
            printf("trig %d !!!\n", fds);
        }
        for(int i = 0; i < fds; i++)
        {
            if(events[i].data.fd == listenfd)
            {
                connfd = accept(listenfd, (sockaddr*)&cliaddr, (socklen_t*)&clilen);
                if(connfd > 0)
                {
                    cout << "new connection from " 
                         << "[" << inet_ntoa(cliaddr.sin_addr) 
                         << ":" << ntohs(cliaddr.sin_port) << "]" 
                         << " accept socket fd:" << connfd 
                         << endl;
                }
                else
                {
                    cout << "accept error, connfd:" << connfd 
                         << " errno:" << errno << endl; 
                }
                fcntl(connfd, F_SETFL, O_NONBLOCK); //no-block io
                ev.data.fd = connfd;
                ev.events = EPOLLIN | EPOLLET;
                if( -1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev))
                    cout << "epoll_ctrl error, errno:" << errno << endl;
            }
            else if(events[i].events & EPOLLIN)
            {
                if((sockfd = events[i].data.fd) < 0)
                {
                    cout << "EPOLLIN sockfd < 0 error " << endl;
                    continue;
                }
                bzero(line, MAX_LINE);
                if((readlength = read(sockfd, line, MAX_LINE)) < 0)
                {
                    if(errno == ECONNRESET)
                    {
                        cout << "ECONNREST closed socket fd:" << events[i].data.fd << endl;
                        close(sockfd);
                    } 
                }
                else if( readlength == 0)
                {
                    cout << "read 0 closed socket fd:" << events[i].data.fd << endl;
                    close(sockfd);
                }
                else
                {
                    printf("read %d, content is %s !!!\n", readlength, line);
                    //if(write(sockfd, line, readlength) != readlength)
                        //cout << "error: not finished one time" << endl;
                }
            }
        }
    }
    return 0;
}
 

你可能感兴趣的:(linux网络编程)