linux—epoll

一、epoll服务端实现中需要的3个函数:

  • epoll_create:创建保存epoll文件描述符的空间。
  • epoll_ctl:向空间注册并注销文件描述符。
  • epoll_wait:与select函数类似,等待文件描述符发生变化。

二、示例

回声服务端:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 #include <sys/epoll.h>
 8 
 9 #define BUF_SIZE 1024
10 #define EPOLL_SIZE 50
11 void error_handling(char * messages);
12 
13 int main(int argc, char *argv[])
14 {
15     if(argc != 2)
16     {
17         printf("Usage : %s <port>\n", argv[0]);
18         exit(1);
19     }
20     int serverSock, clientSock;
21     struct sockaddr_in serverAddr, clientAddr;
22     socklen_t clientAddrSize;
23 
24     char buf[BUF_SIZE];
25     int strLen;
26 
27     struct epoll_event *ep_events;
28     struct epoll_event event;
29     int epfd, event_cnt;
30 
31     serverSock =socket(PF_INET, SOCK_STREAM, 0);
32     if(serverSock == -1)
33         error_handling("socket() error");
34 
35     memset(&serverAddr, 0, sizeof(serverAddr));
36     serverAddr.sin_family = AF_INET;
37     serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
38     serverAddr.sin_port = htons(atoi(argv[1]));
39 
40     if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
41         error_handling("bind() error");
42     if(listen(serverSock, 5) == -1)
43         error_handling("listen() error");
44 
45     epfd = epoll_create(EPOLL_SIZE);
46     ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
47 
48     event.events = EPOLLIN;
49     event.data.fd = serverSock;
50     epoll_ctl(epfd, EPOLL_CTL_ADD, serverSock, &event);
51 
52     puts("Server start...");
53     while(1){
54         event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
55         if(event_cnt == -1){
56             puts("epoll_wait() error");
57             break;
58         }
59         for(int i = 0; i < event_cnt; i++){
60             if(ep_events[i].data.fd == serverSock){
61                 clientAddrSize = sizeof(clientAddr);
62                 clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrSize);
63                 event.events = EPOLLIN;
64                 event.data.fd = clientSock;
65                 epoll_ctl(epfd, EPOLL_CTL_ADD, clientSock, &event);
66                 printf("connected client: %d\n", clientSock);
67             }
68             else{
69                 strLen = read(ep_events[i].data.fd, buf, BUF_SIZE);
70                 if(strLen == 0){
71                     epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
72                     close(ep_events[i].data.fd);
73                     printf("closed client: %d\n", ep_events[i].data.fd);
74                 }
75                 else{
76                     write(ep_events[i].data.fd, buf, strLen);
77                     puts("echo");
78                 }
79             }
80         }
81     }
82     close(serverSock);
83     puts("Server close...");
84     return 0;
85 }
86 
87 void error_handling(char * messages)
88 {
89     puts(messages);
90     exit(1);
91 }
View Code

三、条件触发和边缘触发

  条件触发方式中,只要输入缓冲有数据就会一直通知该事件。

  边缘触发方式中输入缓冲收到数据时仅注册一次该事件。即使输入缓冲中还留有数据,也不会再进行注册。

  select模型是以条件触发的方式工作的。

  epoll默认是以条件触发方式工作的。

  若将文件(套接字)改为非阻塞模式。调用read&write函数时,无论是否存在数据,都会形成非阻塞文件(套接字)。

  边缘触发方式下,以阻塞方式工作的read&write函数又可能引起服务器端的长事件停顿。因此,边缘触发方式中一定要采用非阻塞read&write函数。

边缘触发的回声服务端:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <arpa/inet.h>
  6 #include <sys/socket.h>
  7 #include <sys/epoll.h>
  8 #include <fcntl.h>
  9 #include <errno.h>
 10 
 11 #define BUF_SIZE 4
 12 #define EPOLL_SIZE 50
 13 void setnonblockingmode(int fd);
 14 void error_handling(char * messages);
 15 
 16 int main(int argc, char *argv[])
 17 {
 18     if(argc != 2)
 19     {
 20         printf("Usage : %s <port>\n", argv[0]);
 21         exit(1);
 22     }
 23     int serverSock, clientSock;
 24     struct sockaddr_in serverAddr, clientAddr;
 25     socklen_t clientAddrSize;
 26 
 27     char buf[BUF_SIZE];
 28     int strLen;
 29 
 30     struct epoll_event *ep_events;
 31     struct epoll_event event;
 32     int epfd, event_cnt;
 33 
 34     serverSock =socket(PF_INET, SOCK_STREAM, 0);
 35     if(serverSock == -1)
 36         error_handling("socket() error");
 37 
 38     memset(&serverAddr, 0, sizeof(serverAddr));
 39     serverAddr.sin_family = AF_INET;
 40     serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 41     serverAddr.sin_port = htons(atoi(argv[1]));
 42 
 43     if(bind(serverSock, (struct sockaddr*) &serverAddr, sizeof(serverAddr)) == -1)
 44         error_handling("bind() error");
 45     if(listen(serverSock, 5) == -1)
 46         error_handling("listen() error");
 47 
 48     epfd = epoll_create(EPOLL_SIZE);
 49     ep_events = (struct epoll_event*)malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
 50 
 51     setnonblockingmode(serverSock);
 52     event.events = EPOLLIN;
 53     event.data.fd = serverSock;
 54     epoll_ctl(epfd, EPOLL_CTL_ADD, serverSock, &event);
 55 
 56     puts("Server start...");
 57     while(1){
 58         event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
 59         if(event_cnt == -1){
 60             puts("epoll_wait() error");
 61             break;
 62         }
 63         puts("return epoll_wait");
 64         for(int i = 0; i < event_cnt; i++){
 65             if(ep_events[i].data.fd == serverSock){
 66                 clientAddrSize = sizeof(clientAddr);
 67                 clientSock = accept(serverSock, (struct sockaddr*)&clientAddr, &clientAddrSize);
 68                 setnonblockingmode(clientSock);
 69                 event.events = EPOLLIN|EPOLLET;
 70                 event.data.fd = clientSock;
 71                 epoll_ctl(epfd, EPOLL_CTL_ADD, clientSock, &event);
 72                 printf("connected client: %d\n", clientSock);
 73             }
 74             else{
 75                 while(1)
 76                 {
 77                     strLen = read(ep_events[i].data.fd, buf, BUF_SIZE);
 78                     if(strLen == 0){
 79                         epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
 80                         close(ep_events[i].data.fd);
 81                         printf("closed client: %d\n", ep_events[i].data.fd);
 82                         break;
 83                     }
 84                     else if(strLen < 0){
 85                         if(errno == EAGAIN)
 86                             break;
 87                         else
 88                             puts("???????");
 89                     }
 90                     else{
 91                         write(ep_events[i].data.fd, buf, strLen);
 92                     }
 93                 }
 94             }
 95         }
 96     }
 97     close(serverSock);
 98     puts("Server close...");
 99     return 0;
100 }
101 
102 void setnonblockingmode(int fd) // 套接字改成非阻塞的
103 {
104     int flag = fcntl(fd, F_GETFL, 0);
105     fcntl(fd, F_SETFL, flag|O_NONBLOCK);
106 }
107 
108 void error_handling(char * messages)
109 {
110     puts(messages);
111     exit(1);
112 }
View Code

猜你喜欢

转载自www.cnblogs.com/ACGame/p/10662827.html