zoukankan      html  css  js  c++  java
  • Epoll实现服务端开发

    1.Epoll事件的触发模式

      1.Level Trigger没有处理反复发送(效率低,开发简单,select/epoll默认触发模式)

      2.Edge Trigger只发送一次(效率高,开发困难)

    2.Epoll重要的API

      1.int epoll_create();

      2.int epoll_ctl(epfd, op, fd, struct epoll_event* event);

      3.int epoll_wait(epfd, events, maxevents, timeout);

    3.Epoll的事件

      1.EPOLLET     边缘触发

      2.EPOLLIN   读事件

      3.EPOLLOUT    写事件

      4.EPOLLPRI   服务中断

      5.EPOLLERR  读写出错

      6.EPOLLHUP  服务挂起

    4.epoll_ctl相关操作

      1.EPOLL_CTL_ADD  添加文件描述符

      2.EPOLL_CTL_MOD   修改已存在的描述符

      3.EPOLL_CTL_DEL      删除已存在的描述符

    5.Epoll重要结构体

     1 typedef union epoll_data {
     2   void* ptr;
     3   int     fd;
     4   uint32_t  u32;
     5   uint64_t  u64;
     6 } epoll_data_t;
     7 
     8 struct epoll_event {
     9   uint32_t  events;    // epoll events
    10   epoll_data_t  data;  // user data variable
    11 };

    6.epoll实现高性能网络服务器

      1 /**
      2   epoll.c
      3 */
      4 #include <stdio.h>
      5 #include <errno.h>
      6 #include <unistd.h>
      7 #include <fcntl.h>
      8 #include <string.h>
      9 #include <strings.h>
     10 #include <sys/types.h>
     11 #include <sys/socket.h>
     12 #include <netinet/in.h>
     13 #include <sys/epoll.h>
     14 
     15 #define PORT 8111
     16 #define MSG_LEN 1024
     17 #define MAX_EVENTS 20
     18 #define TIMEOUT 500
     19 
     20 int main(int argc, char* argv[])
     21 {
     22     int ret = -1;
     23     int on = 1;
     24     int backlog = 10;
     25     int flags = 1;
     26     int socket_fd = -1;
     27     int epoll_fd = -1;;
     28     int event_num = 0;
     29     struct epoll_event ev, events[MAX_EVENTS];
     30     struct sockaddr_in    local_addr, remote_addr;
     31     char buff[MSG_LEN] = { 0 };
     32 
     33     socket_fd = socket(AF_INET, SOCK_STREAM, 0);
     34     if (socket_fd < 0) {
     35         printf("create socket fd failed.
    ");
     36         _exit(-1);
     37     }
     38 
     39     flags = fcntl(socket_fd, F_GETFL, 0);
     40     fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
     41 
     42     ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
     43     if (ret < 0) {
     44         printf("set socket option failed.
    ");
     45     }
     46 
     47     bzero(&local_addr, sizeof(local_addr));
     48     local_addr.sin_family = AF_INET;
     49     local_addr.sin_port = htons(PORT);
     50     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     51     ret = bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr));
     52     if (ret < 0) {
     53         printf("bind port[%d] failed.
    ", PORT);
     54         _exit(-1);
     55     }
     56 
     57     ret = listen(socket_fd, backlog);
     58     if (ret < 0) {
     59         printf("listen socket[%d] port[%d] failed.
    ", socket_fd, PORT);
     60         _exit(-1);
     61     }
     62     printf("listening on port[%d]...
    ", PORT);
     63 
     64     epoll_fd = epoll_create(256);
     65     ev.events = EPOLLIN;
     66     ev.data.fd = socket_fd;
     67     epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &ev);
     68 
     69     while (1) {
     70         event_num = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT);
     71         for (int i = 0; i < event_num; ++i)
     72         {
     73             if (events[i].data.fd == socket_fd) {
     74                 socklen_t addr_len = sizeof(struct sockaddr);
     75                 int accept_fd = accept(socket_fd, (struct sockaddr *)&remote_addr, &addr_len);
     76                 flags = fcntl(accept_fd, F_GETFL, 0);
     77                 fcntl(accept_fd, F_SETFL, flags | O_NONBLOCK);
     78                 ev.events = EPOLLIN | EPOLLET;
     79                 ev.data.fd = accept_fd;
     80                 epoll_ctl(epoll_fd, EPOLL_CTL_ADD, accept_fd, &ev);
     81                 printf("connection[%d] estasblished...
    ", accept_fd);
     82             } else if (events[i].events & EPOLLIN) {
     83                 memset(buff, 0, sizeof(buff));
     84                 ret = recv(events[i].data.fd, (void *)buff, sizeof(buff), 0);
     85 
     86                 if (ret <= 0) {
     87                     switch (errno) {
     88                         case EAGAIN:
     89                             printf("receive EAGAIN, break...
    ");
     90                             break;
     91                         case EINTR:
     92                             do {
     93                                 printf("index[%d] fd[%d] receive EINTR, rereceive...
    ", i, events[i].data.fd);
     94                                 memset(buff, 0, sizeof(buff));
     95                                 ret = recv(events[i].data.fd, (void *)buff, sizeof(buff), 0);
     96                             } while (ret < 0 && errno == EINTR);
     97                             break;
     98                         default:
     99                             printf("receive ret[%d] fd[%d] errno[%d|%s]
    ", ret, events[i].data.fd, errno, strerror(errno));
    100                             close(events[i].data.fd);
    101                             ev.events = EPOLLIN | EPOLLET;
    102                             ev.data.fd = events[i].data.fd;
    103                             epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
    104                             break;
    105                     }
    106                 } 
    107 
    108                 if (ret > 0) {
    109                     if (ret == MSG_LEN){
    110                         printf("maybe more data...
    ");
    111                     }
    112 
    113                     buff[ret] = '';
    114                     printf("recv[%s]
    ", buff);
    115                     send(events[i].data.fd, (void *)buff, strlen(buff), 0);
    116                 }
    117             }
    118         }
    119     }
    120 
    121     close(socket_fd);
    122 
    123     return 0;
    124 }
    125 
    126 # gcc -std=c11 -g -o epoll epoll.c
    127 # ./epoll

    7.epoll + fork

      1.在服务开始的时候创建进程池,在运行时创建会很耗时

      2.进程/线程可以与CPU进行绑定,使得CPU主核处理更多的工作

      3.会出现惊群现象,将监听任务放在主进程中,子进程负责数据的收发

      4.或者在某一时刻只有一个进程执行监听任务

      5.使用互斥量;

      1 /**
      2   epoll_fork.c
      3 */
      4 #include <stdio.h>
      5 #include <errno.h>
      6 #include <unistd.h>
      7 #include <fcntl.h>
      8 #include <string.h>
      9 #include <strings.h>
     10 #include <sys/types.h>
     11 #include <sys/wait.h>
     12 #include <sys/socket.h>
     13 #include <netinet/in.h>
     14 #include <sys/epoll.h>
     15 
     16 #define PORT        8111
     17 #define MSG_LEN     1024
     18 #define MAX_EVENTS  20
     19 #define TIMEOUT     500
     20 #define MAX_PROCESS 5
     21 
     22 int main(int argc, char* argv[])
     23 {
     24     int ret = -1;
     25     int on = 1;
     26     int backlog = 10;
     27     int flags = 1;
     28     pid_t pid = -1;
     29     int socket_fd = -1;
     30     int epoll_fd = -1;;
     31     int event_num = 0;
     32     struct epoll_event ev, events[MAX_EVENTS];
     33     struct sockaddr_in    local_addr, remote_addr;
     34     char buff[MSG_LEN] = { 0 };
     35 
     36     socket_fd = socket(AF_INET, SOCK_STREAM, 0);
     37     if (socket_fd < 0) {
     38         printf("create socket fd failed.
    ");
     39         _exit(-1);
     40     }
     41 
     42     flags = fcntl(socket_fd, F_GETFL, 0);
     43     fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
     44 
     45     ret = setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
     46     if (ret < 0) {
     47         printf("set socket option failed.
    ");
     48     }
     49 
     50     bzero(&local_addr, sizeof(local_addr));
     51     local_addr.sin_family = AF_INET;
     52     local_addr.sin_port = htons(PORT);
     53     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     54     ret = bind(socket_fd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr));
     55     if (ret < 0) {
     56         printf("bind port[%d] failed.
    ", PORT);
     57         _exit(-1);
     58     }
     59 
     60     ret = listen(socket_fd, backlog);
     61     if (ret < 0) {
     62         printf("listen socket[%d] port[%d] failed.
    ", socket_fd, PORT);
     63         _exit(-1);
     64     }
     65     printf("listening on port[%d]...
    ", PORT);
     66 
     67     
     68 
     69     for (int i = 0; i < MAX_PROCESS; ++i)
     70     {
     71         // father process
     72         if (pid != 0) {
     73             pid = fork();
     74         }
     75     }
     76 
     77     if (pid == 0) {
     78         epoll_fd = epoll_create(256);
     79         ev.events = EPOLLIN;
     80         ev.data.fd = socket_fd;
     81         epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &ev);
     82 
     83         while (1) {
     84             event_num = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT);
     85             for (int i = 0; i < event_num; ++i)
     86             {
     87                 if (events[i].data.fd == socket_fd) {
     88                     printf("socket fd[%d] coming...
    ", socket_fd);
     89                     socklen_t addr_len = sizeof(struct sockaddr);
     90                     int accept_fd = accept(socket_fd, (struct sockaddr *)&remote_addr, &addr_len);
     91                     flags = fcntl(accept_fd, F_GETFL, 0);
     92                     fcntl(accept_fd, F_SETFL, flags | O_NONBLOCK);
     93                     ev.events = EPOLLIN | EPOLLET;
     94                     ev.data.fd = accept_fd;
     95                     epoll_ctl(epoll_fd, EPOLL_CTL_ADD, accept_fd, &ev);
     96                     printf("connection[%d] estasblished...
    ", accept_fd);
     97                 } else if (events[i].events & EPOLLIN) {
     98                     memset(buff, 0, sizeof(buff));
     99                     ret = recv(events[i].data.fd, (void *)buff, sizeof(buff), 0);
    100 
    101                     if (ret <= 0) {
    102                         switch (errno) {
    103                             case EAGAIN:
    104                                 printf("receive EAGAIN, break...
    ");
    105                                 break;
    106                             case EINTR:
    107                                 do {
    108                                     printf("index[%d] fd[%d] receive EINTR, rereceive...
    ", i, events[i].data.fd);
    109                                     memset(buff, 0, sizeof(buff));
    110                                     ret = recv(events[i].data.fd, (void *)buff, sizeof(buff), 0);
    111                                 } while (ret < 0 && errno == EINTR);
    112                                 break;
    113                             default:
    114                                 printf("receive ret[%d] fd[%d] errno[%d|%s]
    ", ret, events[i].data.fd, errno, strerror(errno));
    115                                 close(events[i].data.fd);
    116                                 ev.events = EPOLLIN | EPOLLET;
    117                                 ev.data.fd = events[i].data.fd;
    118                                 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
    119                                 break;
    120                         }
    121                     } 
    122 
    123                     if (ret > 0) {
    124                         if (ret == MSG_LEN){
    125                             printf("maybe more data...
    ");
    126                         }
    127 
    128                         buff[ret] = '';
    129                         printf("recv[%s]
    ", buff);
    130                         send(events[i].data.fd, (void *)buff, strlen(buff), 0);
    131                     }
    132                 }
    133             }
    134         }
    135     } else {
    136         do {
    137             pid = waitpid(-1, NULL, 0);
    138             printf("child pid[%d]
    ", pid);
    139         } while (pid != -1);
    140         close(socket_fd);
    141     }
    142 
    143     return 0;
    144 }
    145 
    146 # gcc -std=c11 -g -o epoll_fork epoll_fork.c
    147 # ./epoll_fork

      关于绑定CPU核epoll惊群的代码后面有时间再进行补充。

  • 相关阅读:
    TextView 高亮
    Android 学习 第一章(环境搭建)
    从assets res 中读文件
    动态设置imageview 宽高
    android 算定义view 打包 jar(一次开发多次使用)
    Activity 跳转
    Android手机在开发调试时logcat不显示输出信息的解决办法
    弹出对话 AlertDialog 有按钮
    让划动 listview时 没有黑色背景
    Activity Service 数据相互操作
  • 原文地址:https://www.cnblogs.com/sip-inaction/p/13173242.html
Copyright © 2011-2022 走看看