epoll的一點思考(2)

來源:互聯網
上載者:User

epoll out事件觸發時機

當epoll_ctl設定了out事件(add 或 mod),如果核心發送緩衝區有空閑,則會觸發out事件,如果發送緩衝區滿,則不會不會觸發out事件,當發送緩衝區不再滿時會觸發out事件。如果在緩衝區由滿變為不滿之前不設定out事件(mod 修改out->in),在緩衝區不滿之後不會觸發out事件。

第一種情況,設定out,測試代碼如下:

#include <iostream>#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <errno.h>using namespace std;#define MAXLINE 5#define OPEN_MAX 100#define LISTENQ 20#define SERV_PORT 6002#define INFTIM 1000void setnonblocking(int sock){    int opts;    opts=fcntl(sock,F_GETFL);    if(opts<0)    {        perror("fcntl(sock,GETFL)");        exit(1);    }    opts = opts|O_NONBLOCK;    if(fcntl(sock,F_SETFL,opts)<0)    {        perror("fcntl(sock,SETFL,opts)");        exit(1);    }   }int main(){    int i, maxi, listenfd, connfd, sockfd,epfd,nfds;    ssize_t n;    char line[MAXLINE];    socklen_t clilen;    //聲明epoll_event結構體的變數,ev用於註冊事件,數組用於回傳要處理的事件    struct epoll_event ev,events[20];    //產生用於處理accept的epoll專用的檔案描述符    epfd=epoll_create(256);    struct sockaddr_in clientaddr;    struct sockaddr_in serveraddr;    listenfd = socket(AF_INET, SOCK_STREAM, 0);    int reuse = 1;    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));    //把socket設定為非阻塞方式    //setnonblocking(listenfd);    //設定與要處理的事件相關的檔案描述符    ev.data.fd=listenfd;    //設定要處理的事件類型    ev.events=EPOLLIN|EPOLLET;    //ev.events=EPOLLIN;    //註冊epoll事件    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);    bzero(&serveraddr, sizeof(serveraddr));    serveraddr.sin_family = AF_INET;    char *local_addr="0.0.0.0";    inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);    serveraddr.sin_port=htons(SERV_PORT);    bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));    listen(listenfd, LISTENQ);    maxi = 0;    for ( ; ; ) {        //等待epoll事件的發生        nfds=epoll_wait(epfd,events,20,-1);        //處理所發生的所有事件             for(i=0;i<nfds;++i)        {            if(events[i].data.fd==listenfd)            {                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);                setnonblocking(connfd);                if(connfd<0){                    perror("connfd<0");                    exit(1);                }                setnonblocking(connfd);                char *str = inet_ntoa(clientaddr.sin_addr);                cout << "accapt a connection from " << str << endl;                                //設定用於讀操作的檔案描述符                ev.data.fd=connfd;                //設定用於注測的讀操作事件                ev.events=EPOLLOUT|EPOLLET;                //ev.events=EPOLLIN;                //註冊ev                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);                                char buf[1024] = "abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890";                int i = 0;                while(1)                {                    if (send(connfd, buf, strlen(buf) + 1, 0) < 0)                    {                        cout << "error-->" << strerror(errno) << endl;                        break;                    }                    usleep(100000);                    cout <<  ++i << endl;                }            }            else if(events[i].events&EPOLLIN)            {                cout << "EPOLLIN" << endl;                                sockfd = events[i].data.fd;                char buf;                       int n = 0;                        while ( (n = read(sockfd, &buf, 1)) > 0)                 {                    printf("%c\n",buf);                                    }                printf("%d\n",n);                if (n == 0)                {                    ev.data.fd=sockfd;                                      epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);                } else                {                    ev.data.fd=sockfd;                    ev.events=EPOLLET|EPOLLOUT;                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);                }                            }            else if(events[i].events&EPOLLOUT)            {                cout << "EPOLLOUT" << endl;                                                       sockfd = events[i].data.fd;                //write(sockfd, line, n);                //設定用於讀操作的檔案描述符                // sleep(5);                ev.data.fd=sockfd;                //設定用於注測的讀操作事件                ev.events=EPOLLIN|EPOLLET;                //修改sockfd上要處理的事件為EPOLIN                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);            }        }    }    return 0;}

用戶端使用telnet 命令,telnet 192.168.0.123 6002,串連後會收到資料,使用加強工作管理員將telnet進程掛起,不再列印輸出,server一直發送資料,直到Resource temporarily unavailable,退出while迴圈,等待out事件,在加強任務管理中喚醒telnet ,會列印出EPOLLOUT,說明發送緩衝區由滿到不滿,會觸發out事件。

第二種情況:在緩衝區由滿變為不滿之前修改out 為 in,測試代碼如下:

#include <iostream>#include <sys/socket.h>#include <sys/epoll.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <errno.h>using namespace std;#define MAXLINE 5#define OPEN_MAX 100#define LISTENQ 20#define SERV_PORT 6002#define INFTIM 1000void setnonblocking(int sock){    int opts;    opts=fcntl(sock,F_GETFL);    if(opts<0)    {        perror("fcntl(sock,GETFL)");        exit(1);    }    opts = opts|O_NONBLOCK;    if(fcntl(sock,F_SETFL,opts)<0)    {        perror("fcntl(sock,SETFL,opts)");        exit(1);    }   }int main(){    int i, maxi, listenfd, connfd, sockfd,epfd,nfds;    ssize_t n;    char line[MAXLINE];    socklen_t clilen;    //聲明epoll_event結構體的變數,ev用於註冊事件,數組用於回傳要處理的事件    struct epoll_event ev,events[20];    //產生用於處理accept的epoll專用的檔案描述符    epfd=epoll_create(256);    struct sockaddr_in clientaddr;    struct sockaddr_in serveraddr;    listenfd = socket(AF_INET, SOCK_STREAM, 0);    int reuse = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));    //把socket設定為非阻塞方式    //setnonblocking(listenfd);    //設定與要處理的事件相關的檔案描述符    ev.data.fd=listenfd;    //設定要處理的事件類型    ev.events=EPOLLIN|EPOLLET;    //ev.events=EPOLLIN;    //註冊epoll事件    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);    bzero(&serveraddr, sizeof(serveraddr));    serveraddr.sin_family = AF_INET;    char *local_addr="0.0.0.0";    inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);    serveraddr.sin_port=htons(SERV_PORT);    bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));    listen(listenfd, LISTENQ);    maxi = 0;    for ( ; ; ) {        //等待epoll事件的發生        nfds=epoll_wait(epfd,events,20,-1);        //處理所發生的所有事件             for(i=0;i<nfds;++i)        {            if(events[i].data.fd==listenfd)            {                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);        setnonblocking(connfd);                if(connfd<0){                    perror("connfd<0");                    exit(1);                }                //setnonblocking(connfd);                char *str = inet_ntoa(clientaddr.sin_addr);                cout << "accapt a connection from " << str << endl;                                //設定用於讀操作的檔案描述符                ev.data.fd=connfd;                //設定用於注測的讀操作事件                ev.events=EPOLLOUT|EPOLLET;                //ev.events=EPOLLIN;                //註冊ev                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);                                char buf[1024] = "abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890abc1234567890";                int i = 0;                while(1)                {                    if (send(connfd, buf, strlen(buf) + 1, 0) < 0)                    {                        cout << "error-->" << strerror(errno) << endl;                        break;                    }                    usleep(100000);                    cout <<  ++i << endl;                }                 //設定用於注測的讀操作事件                ev.events=EPOLLIN|EPOLLET;                //ev.events=EPOLLIN;                //註冊ev                epoll_ctl(epfd,EPOLL_CTL_MOD,connfd,&ev);            }            else if(events[i].events&EPOLLIN)            {                cout << "EPOLLIN" << endl;                              sockfd = events[i].data.fd;                char buf;                       int n = 0;                        while ( (n = read(sockfd, &buf, 1)) > 0)                 {                    printf("%c\n",buf);                                    }                printf("%d\n",n);                if (n == 0)                {                    ev.data.fd=sockfd;                                      epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);                } else                {                    ev.data.fd=sockfd;                    ev.events=EPOLLET|EPOLLOUT;                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);                }                           }            else if(events[i].events&EPOLLOUT)            {                cout << "EPOLLOUT" << endl;                 sockfd = events[i].data.fd;                //write(sockfd, line, n);                //設定用於讀操作的檔案描述符                // sleep(5);                ev.data.fd=sockfd;                //設定用於注測的讀操作事件                ev.events=EPOLLIN|EPOLLET;                //修改sockfd上要處理的事件為EPOLIN                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);                }        }    }    return 0;}

用戶端使用telnet 命令,telnet 192.168.0.123 6002,串連後會收到資料,使用加強工作管理員將telnet進程掛起,不再列印輸出,server一直發送資料,直到Resource temporarily unavailable,退出while迴圈,等待out事件,在加強任務管理中喚醒telnet ,不會有任何輸出。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.