epoll学习
一、epoll_create
#include <sys/epoll.h>int epoll_create(int size); int epoll_create1(int flags); 返回:成功非負文件描述符,-1出錯size:內核監聽數目一共多大
創建一個epoll接口,size參數和select不同,不是fd+1?
需要注意的是:當創建好epoll后,它就會占用一個fd值,在linux /proc/id/fd/能看到這個fd的,所以使用完epoll后,必須close()關閉,否則可能導致耗盡fd。
?
二、epoll_ctl
#include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 返回:0成功,-1失敗epfd:由epoll_create生成的epoll專用的文件描述符
op:要進行的操作,可能取EPOLL_CTL_ADD注冊、EPOLL_CTL_MOD修改、EPOLL_CTL_DEL刪除
fd:關聯的文件描述符
event:指向epoll_event指針
?epoll的相關的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 events */epoll_data_t data; /* User data variable */ };其中的events可以是以下幾個宏的集合:
EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符可以寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這里應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對于水平觸發(Level Triggered)來說的。
EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之后,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列里
三、epoll_wait
#include <sys/epoll.h>int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);int epoll_pwait(int epfd, struct epoll_event *events,int maxevents, int timeout, const sigset_t *sigmask);返回:發生事件數
epfd:由epoll_create生成的epoll專用的文件描述符
epoll_event:用于回傳代處理事件的數組
maxevents:每次能處理的事件數
timeout:等待I/O事件發生的超時值
?
在linux中的man手冊中有epoll模型:
1 #define MAX_EVENTS 10 2 struct epoll_event ev, events[MAX_EVENTS]; 3 int listen_sock, conn_sock, nfds, epollfd; 4 5 /* Set up listening socket, 'listen_sock' (socket(), 6 bind(), listen()) */ 7 8 epollfd = epoll_create(10); 9 if (epollfd == -1) { 10 perror("epoll_create"); 11 exit(EXIT_FAILURE); 12 } 13 14 ev.events = EPOLLIN; 15 ev.data.fd = listen_sock; 16 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) { 17 perror("epoll_ctl: listen_sock"); 18 exit(EXIT_FAILURE); 19 } 20 21 for (;;) { 22 nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); //等待IO事件 23 if (nfds == -1) { 24 perror("epoll_pwait"); 25 exit(EXIT_FAILURE); 26 } 27 28 for (n = 0; n < nfds; ++n) { 29 //如果是主socket事件,則表示有新連接進入,需要進行新連接的處理 30 if (events[n].data.fd == listen_sock) { 31 conn_sock = accept(listen_sock, 32 (struct sockaddr *) &local, &addrlen); 33 if (conn_sock == -1) { 34 perror("accept"); 35 exit(EXIT_FAILURE); 36 } 37 //將新連接置于非阻塞模式 38 setnonblocking(conn_sock); 39 ev.events = EPOLLIN | EPOLLET; 40 //注意這里的參數EPOLLIN|EPOLLET并沒有設置對寫socket的監聽 41 //如果有寫操作的話,這個時候epoll是不會返回事件的 42 //如果要對寫操作也監聽的話,應該是EPOLLIN|EPOLLOUT|EPOLLET 43 //并且將新連接也加入EPOLL的監聽隊列 44 ev.data.fd = conn_sock; 45 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, 46 &ev) == -1) { 47 //加入到epoll的監聽隊列里,這里用EPOLL_CTL_ADD 48 //來加一個新的epoll事件,可以通過EPOLL_CTL_DEL減少 49 //一個epoll事件,通過EPOLL_CTL_MOD來改變一個i額事件的監聽方式 50 perror("epoll_ctl: conn_sock"); 51 exit(EXIT_FAILURE); 52 } 53 } else { 54 //如果不是主socket的事件的話,則代表這是一個用戶的socket事件 55 //則用來處理這個用戶的socket的事情是,比如說read(fd, xxx)之類,或者一些其他的處理 56 do_use_fd(events[n].data.fd); 57 } 58 } 59 } epoll模型?下面是個epoll的使用例子:
1 #include <iostream> 2 #include <sys/socket.h> 3 #include <sys/epoll.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <fcntl.h> 7 #include <unistd.h> 8 #include <stdio.h> 9 #include <errno.h> 10 #include <stdlib.h> 11 #include <strings.h> 12 13 using namespace std; 14 15 #define MAXLINE 5 16 #define OPEN_MAX 100 17 #define LISTENQ 20 18 #define SERV_PORT 5000 19 #define INFTIM 1000 20 21 void setnonblocking(int sock) 22 { 23 int opts; 24 opts = fcntl(sock, F_GETFL); 25 if(opts < 0) { 26 perror("fcntl(sock, GETFL)"); 27 exit(1); 28 } 29 opts = opts | O_NONBLOCK; 30 if(fcntl(sock, F_SETFL, opts) < 0) { 31 perror("fcntl(sock, SETFL, opts)"); 32 exit(1); 33 } 34 } 35 36 int main() 37 { 38 int i, maxi, listenfd, connfd, sockfd, epfd, nfds; 39 ssize_t n; 40 char line[MAXLINE]; 41 socklen_t clilen; 42 43 struct epoll_event ev, events[20]; 44 epfd = epoll_create(256); 45 struct sockaddr_in clientaddr; 46 struct sockaddr_in serveraddr; 47 listenfd = socket(AF_INET, SOCK_STREAM, 0); 48 49 setnonblocking(listenfd); 50 ev.data.fd = listenfd; 51 ev.events = EPOLLIN | EPOLLET; 52 epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); 53 bzero(&serveraddr, sizeof(serveraddr)); 54 serveraddr.sin_family = AF_INET; 55 char *local_addr = "192.168.1.63"; 56 inet_aton(local_addr, &(serveraddr.sin_addr)); 57 serveraddr.sin_port = htons(SERV_PORT); 58 bind(listenfd, (sockaddr *)&serveraddr, sizeof(serveraddr)); 59 listen(listenfd, LISTENQ); 60 61 maxi = 0; 62 for( ; ; ) { 63 nfds = epoll_wait(epfd, events, 20, 500); 64 for(i=0;i<nfds;i++) { 65 if(events[i].data.fd == listenfd) { 66 connfd = accept(listenfd, (sockaddr *)&clientaddr, &clilen); 67 if(connfd < 0) { 68 perror("connfd < 0"); 69 exit(1); 70 } 71 setnonblocking(connfd); 72 char *str = inet_ntoa(clientaddr.sin_addr); 73 std::cout<<"connect from"<<str<<std::endl; 74 ev.data.fd = connfd; 75 ev.events = EPOLLIN | EPOLLET; 76 epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev); 77 } else if(events[i].events & EPOLLIN) { 78 if((sockfd = events[i].data.fd) < 0) { 79 continue; 80 } 81 if((n = read(sockfd, line, MAXLINE)) < 0) { 82 if(errno == ECONNRESET) { 83 close(sockfd); 84 events[i].data.fd = -1; 85 } else { 86 std::cout<<"readline error"<<std::endl; 87 } 88 } else if(n == 0) { 89 close(sockfd); 90 events[i].data.fd = -1; 91 } 92 ev.data.fd = sockfd; 93 ev.events = EPOLLOUT | EPOLLET; 94 epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); 95 } else if(events[i].events & EPOLLOUT) { 96 sockfd = events[i].data.fd; 97 write(sockfd, line, n); 98 ev.data.fd = sockfd; 99 ev.events = EPOLLIN | EPOLLET; 100 epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); 101 } 102 } 103 } 104 } epoll例子?
轉載于:https://www.cnblogs.com/ch122633/p/8457782.html
總結
- 上一篇: Windows 10 IoT Core
- 下一篇: 配置Ubuntu虚拟环境