epoll的一点思考(5)

来源:互联网 发布:射频电路仿真软件 编辑:程序博客网 时间:2024/05/16 10:07

epoll 同时触发in与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>#include <netinet/tcp.h>using namespace std;#define MAXLINE 5#define OPEN_MAX 100#define LISTENQ 20#define SERV_PORT 6002#define INFTIM 1000int socket_set_keepalive( int fd){    int ret, error, flag, alive, idle, cnt, intv;        /* Set: use keepalive on fd */    alive = 1;    if (setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &alive, sizeof alive) != 0)    {        printf ("Set keepalive error: %s.\n" , strerror (errno));        return -1;    }        /* 10秒钟无数据,触发保活机制,发送保活包 */    idle = 10;    if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE , &idle, sizeof idle) != 0)    {        printf ("Set keepalive idle error: %s.\n" , strerror (errno));        return -1;    }        /* 如果没有收到回应,则5秒钟后重发保活包 */    intv = 5;    if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL , &intv, sizeof intv) != 0)    {        printf ("Set keepalive intv error: %s.\n", strerror (errno));        return -1;    }        /* 连续3次没收到保活包,视为连接失效 */    cnt = 3;    if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT , &cnt, sizeof cnt) != 0)    {        printf ("Set keepalive cnt error: %s.\n", strerror (errno));        return -1;    }        return 0;}void 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);    cout << listenfd << endl;    maxi = 0;    for ( ; ; ) {        //等待epoll事件的发生        nfds=epoll_wait(epfd,events,20,-1);        cout << "EPOLL wait end" << endl;        //处理所发生的所有事件             for(i=0;i<nfds;++i)        {            cout << "nfds:" << nfds << endl;            if(events[i].data.fd==listenfd)            {                clilen = sizeof(clientaddr);                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);                        if(connfd<0){                    perror("connfd<0");                    exit(1);                }                  setnonblocking(connfd);                              //socket_set_keepalive(connfd);                char *str = inet_ntoa(clientaddr.sin_addr);                cout << "accapt a connection from " << str << endl;                                //设置用于读操作的文件描述符                ev.data.fd=connfd;                //设置用于注测的读操作事件                ev.events=EPOLLOUT|EPOLLET|EPOLLIN;                //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);               sleep(10);            }            else             {                if(events[i].events&EPOLLIN)                {                    cout << "EPOLLIN" << endl;                    /*                    sockfd = events[i].data.fd;                    char buf;                           int n = 0;                            if ( (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                    {                        cout << "error-222--->" << strerror(errno) << endl;                        ev.data.fd=sockfd;                        ev.events=EPOLLOUT|EPOLLET|EPOLLIN;                        epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);                                        }                       */                                }                if(events[i].events&EPOLLOUT)                {                    cout << "EPOLLOUT" << endl;                                        //cout << "EPOLLOUT END" << endl;                    /*                    sockfd = events[i].data.fd;                    //write(sockfd, line, n);                    //设置用于读操作的文件描述符                    // sleep(5);                    ev.data.fd=sockfd;                    //设置用于注测的读操作事件                    ev.events=EPOLLOUT|EPOLLET|EPOLLIN;                    //修改sockfd上要处理的事件为EPOLIN                    epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);                    */                }             }        }    }    return 0;}

在accept之后监听in与out事件,然后sleep(10),客户端在这10秒内发送数据,等待epoll_wait返回后,分别进入in与out分值,注意if (in) 然后if (out),而不是else if (out)。

原创粉丝点击