Epoll示例

xiaoxiao2021-02-28  82

#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 1000 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() { /* 结构体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; }
转载请注明原文地址: https://www.6miu.com/read-76792.html

最新回复(0)