• 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>
    ", 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
    ", 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
    ", 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>
    ", 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
    ", 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
    ", 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
  • 相关阅读:
    关于Qt国产化系统开发的几点总结
    C#和Qt实现的对于异常处理的一个使用策略
    echarts 自定义省份区块颜色的两种方法
    获取某个文件下的.vue文件
    仿写单选框/多选框
    重置对象属性
    elementUI之树形数据Table遇到的问题
    sass使用记录
    koa的使用记录
    六顶思想帽
  • 原文地址:https://www.cnblogs.com/ACGame/p/10662827.html
Copyright © 2020-2023  润新知