Epoll示例

来源:互联网 发布:汤敏的淘宝店网址 编辑:程序博客网 时间:2024/05/22 03:43
#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 <strings.h>#include <string.h>#include <stdio.h>using namespace std;#define MAXLINE 32#define OPEN_MAX 100#define LISTENQ 20#define SERV_PORT 5555#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(){/*  结构体epoll_event 被用于注册所感兴趣的事件和回传所发生待处理的事件,定义如下:    typedef union epoll_data {        void *ptr;         int fd;         __uint32_t u32;         __uint64_t u64;     } epoll_data_t;//保存触发事件的某个文件描述符相关的数据     struct epoll_event {         __uint32_t events;      // epoll event         epoll_data_t data;      // User data variable     };    其中events表示感兴趣的事件和被触发的事件,可能的取值为:    EPOLLIN :表示对应的文件描述符可以读;    EPOLLOUT:表示对应的文件描述符可以写;    EPOLLPRI: 表示对应的文件描述符有紧急的数可读;    EPOLLERR:表示对应的文件描述符发生错误;    EPOLLHUP:表示对应的文件描述符被挂断;    EPOLLET:    ET的epoll工作模式;*/ssize_t n;char line[MAXLINE];socklen_t clilen;struct epoll_event ev,events[20];int i,maxi,listenfd,connfd,sockfd,epfd,nfds;/*1、epoll_create函数     函数声明:int epoll_create(int size)    功能:该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围;*/epfd = epoll_create(256);struct sockaddr_in clientaddr;struct sockaddr_in serveraddr;listenfd = socket(AF_INET,SOCK_STREAM,0);//设置非阻塞setnonblocking(listenfd);/*2、epoll_ctl函数     函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)     功能:用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。    @epfd:由 epoll_create 生成的epoll专用的文件描述符;     @op:要进行的操作,EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修改、EPOLL_CTL_DEL 删除;     @fd:关联的文件描述符;    @event:指向epoll_event的指针;    成功:0;失败:-1*/ev.data.fd = listenfd;ev.events = EPOLLIN | EPOLLET;epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);//服务器地址绑定bzero(&serveraddr,sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_addr.s_addr = INADDR_ANY;serveraddr.sin_port = htons(1234);bind(listenfd,(const sockaddr*)&serveraddr,sizeof(serveraddr));listen(listenfd,LISTENQ);while(true) {    /*    3、epoll_wait函数    函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)    功能:该函数用于轮询I/O事件的发生;    @epfd:由epoll_create 生成的epoll专用的文件描述符;    @epoll_event:用于回传代处理事件的数组;    @maxevents:每次能处理的事件数;    @timeout:等待I/O事件发生的超时值;    成功:返回发生的事件数;失败:-1    */    nfds = epoll_wait(epfd,events,20,500);    for(i = 0;i < nfds;i ++) {        if(events[i].data.fd == listenfd) {//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。          connfd = accept(listenfd,(sockaddr*)&clientaddr,&clilen);          if(connfd < 0){              perror("connfd<0");              return -1;          }          //设置非阻塞          setnonblocking(listenfd);          printf("ip client:%s\n",inet_ntoa(clientaddr.sin_addr));          ev.data.fd = connfd;          ev.events = EPOLLIN | EPOLLET;          epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);        }else if (events[i].events & EPOLLIN) {//如果是已经连接的用户,并且收到数据,那么进行读入。            if ((sockfd = events[i].data.fd) < 0) continue;//确定连接用户存在            if ((n = read(sockfd,line,MAXLINE))< 0){                if(errno == ECONNRESET) {                    close(sockfd);                    events[i].data.fd = -1;                } else                    cout<<"readline error"<<endl;            }else if (0 == n){                close(sockfd);                events[i].data.fd = -1;            }            printf("Data ==:%s\n",line);            ev.data.fd = sockfd;//修改sockfd事件为EPOLLOUT            ev.events = EPOLLOUT | EPOLLET;            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);        } else if (events[i].events & EPOLLOUT) {            printf("send data to client\n");            sockfd = events[i].data.fd;            write(sockfd,"hello client",n);            ev.data.fd =sockfd;            ev.events = EPOLLIN | EPOLLET;            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);        }    }}return 0;}