zoukankan      html  css  js  c++  java
  • libubox组件(3)——uloop

    一:uloop概述

    • uloop有三个功能: 文件描述符触发事件的监控,  timeout定时器处理, 当前进程的子进程的维护

    二: uloop的整体框架

       1:  /**
       2:   * 初始化事件循环
       3:   *主要工作是poll_fd = epoll_create(32);/* 创建一个epoll的文件描述符监控句柄。最多监控32个文件描述符 
       4:   **/
       5:  int uloop_init(void)
       6:  {
       7:      if (poll_fd >= 0)
       8:          return 0;
       9:   
      10:      poll_fd = epoll_create(32);/* 创建一个epoll的句柄。最多监控32个文件描述符 */
      11:      if (poll_fd < 0)
      12:          return -1;
      13:   
      14:      fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); /* fd_cloexecs */
      15:      return 0;
      16:  }
      17:   
      18:   
      19:  /**
      20:   * 事件循环主处理入口
      21:   *1.当某一个进程第一次调用uloop_run时,注册sigchld和sigint信号
      22:   *2.循环获取当前时间,把超时的timeout处理掉,有一条timeout链表在维护
      23:   *3.循环检测是否收到一个sigchld信号,如果收到,删除对应的子进程,有一条process子进程链表在维护
      24:   *4.循环调用epoll_wait 监相应的触发事件文件描述符fd 
      25:   **/
      26:  void uloop_run(void)
      27:  {
      28:      static int recursive_calls = 0; /* static value */
      29:      struct timeval tv;
      30:   
      31:      /*
      32:       * Handlers are only updated for the first call to uloop_run() (and restored
      33:       * when this call is done).
      34:       */
      35:      if (!recursive_calls++) /* 第一次运行uloop_run时调用, 注册信号处理函数 */
      36:          uloop_setup_signals(true);
      37:   
      38:      uloop_cancelled = false;
      39:      while(!uloop_cancelled)
      40:      {
      41:          uloop_gettime(&tv); /* 获取当前时间 */
      42:          uloop_process_timeouts(&tv); /* 把超时的timeout清理掉 */
      43:          if (uloop_cancelled)
      44:              break;
      45:   
      46:          if (do_sigchld) /*  收到一个sigchld的信号 */
      47:              uloop_handle_processes(); /* 销毁该进程的uloop_process */
      48:          uloop_gettime(&tv);
      49:          uloop_run_events(uloop_get_next_timeout(&tv));/* 处理相应的触发事件fd */
      50:      }
      51:   
      52:      if (!--recursive_calls)
      53:          uloop_setup_signals(false);
      54:  }
      55:   
      56:   
      57:  /**
      58:   * 销毁事件循环
      59:   * 关闭epoll描述符
      60:   * 销毁子进程链表
      61:   * 销毁timeout链表
      62:  **/
      63:  void uloop_done(void)
      64:  {
      65:      if (poll_fd < 0)
      66:          return;
      67:   
      68:      close(poll_fd);
      69:      poll_fd = -1;
      70:   
      71:      uloop_clear_timeouts();
      72:      uloop_clear_processes();
      73:  }
     
     
    三:uloop文件描述符触发事件的监控
       1:  #define ULOOP_READ        (1 << 0)
       2:  #define ULOOP_WRITE        (1 << 1)
       3:  #define ULOOP_EDGE_TRIGGER    (1 << 2)
       4:  #define ULOOP_BLOCKING        (1 << 3)
       5:   
       6:  #define ULOOP_EVENT_MASK    (ULOOP_READ | ULOOP_WRITE)
       7:  /* internal flags */
       8:  #define ULOOP_EVENT_BUFFERED    (1 << 4)
       9:  #define ULOOP_ERROR_CB        (1 << 6)
      10:  struct uloop_fd
      11:  {
      12:      uloop_fd_handler cb; /* 文件描述符对应的处理函数 */
      13:      int fd;                         /*文件描述符*/
      14:      bool eof;                    /*EOF*/
      15:      bool error;                 /*出错*/
      16:      bool registered;        /*是否已经添加到epoll的监控队列*/
      17:      uint8_t flags;           /*ULOOP_READ | ULOOP_WRITE | ULOOP_BLOCKING等*/  
      18:  };
      19:   
      20:  /**
      21:   * 注册一个新描述符到事件处理循环
      22:   */
      23:  int uloop_fd_add(struct uloop_fd *sock, unsigned int flags)
      24:   
      25:  /** 
      26:   * 从事件处理循环中销毁指定描述符
      27:   */
      28:  int uloop_fd_delete(struct uloop_fd *sock)
     
    例子:
       1:  #include <stdio.h>
       2:  #include <stdlib.h>
       3:  #include <string.h>
       4:  #include <unistd.h>
       5:  #include <sys/types.h>          /* See NOTES */
       6:  #include <sys/stat.h>
       7:  #include <fcntl.h>
       8:  #include <sys/socket.h>
       9:  #include <netinet/in.h>
      10:  #include <arpa/inet.h>
      11:  #include <libubox/usock.h>
      12:  #include <libubox/uloop.h> 
      13:  static void recv_string(struct uloop_fd *u, unsigned int events)
      14:  {
      15:      char buf[1024] = {0};
      16:      if (events & ULOOP_READ) {
      17:          if ( recv(u->fd, buf, 1024, 0) > 0) {
      18:              printf("recv_buf: %s
    ", buf);
      19:              send(u->fd, "helloworld from server", strlen("helloworld from server"), 0);
      20:          }
      21:      }
      22:  }
      23:   
      24:  static void read_std(struct uloop_fd *u, unsigned int events)
      25:  {
      26:      char buf[1024] = {0};
      27:      if (events & ULOOP_READ) {
      28:          if ( read(u->fd, buf, 1024) > 0) {
      29:              printf("read_std: %s
    ", buf);
      30:          }
      31:      }
      32:  }
      33:   
      34:  int main()
      35:  {
      36:      struct sockaddr_in cli_addr;
      37:      socklen_t len = sizeof(struct sockaddr);
      38:      int type = USOCK_TCP | USOCK_SERVER  | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
      39:      const char *host = "CarRadio";
      40:      const char *service = "8000";
      41:      char recv_buf[1024] = {0};
      42:      int connect_fd, u_fd = usock(type, host, service);    
      43:      if (u_fd < 0) {
      44:          perror("usock");
      45:          return -1;
      46:      }
      47:      
      48:      connect_fd = accept(u_fd, (struct sockaddr *)(&cli_addr), &len);
      49:      if (connect_fd < 0) {
      50:          perror("accept");
      51:          return -1;
      52:      }
      53:      struct uloop_fd fd[2] = {
      54:          {
      55:              .cb = recv_string,
      56:              .fd = connect_fd,
      57:              .registered = false,
      58:              .flags = ULOOP_READ,
      59:          },
      60:          {
      61:              .cb = read_std,
      62:              .fd = STDIN_FILENO,
      63:              .registered = false,
      64:              .flags = ULOOP_READ,
      65:          }
      66:      };
      67:      uloop_init();
      68:      /*添加uloop_fd*/
      69:      uloop_fd_add(&fd[0], ULOOP_READ);
      70:      uloop_fd_add(&fd[1], ULOOP_READ);
      71:      uloop_run();
      72:   
      73:      uloop_fd_delete(&fd[0]);
      74:      uloop_done();
      75:      
      76:      return 0;
      77:  }

    四:timeout定时器处理

    建立一条链表管理所有的timeout节点

       1:  struct uloop_timeout
       2:  {
       3:      struct list_head list;  //链表节点
       4:      bool pending;           //添加一个新的timeout pending是true, false删除该节点timeout
       5:   
       6:      uloop_timeout_handler cb; //超时处理函数
       7:      struct timeval time;       //超时时间
       8:  };
       9:   
      10:  /**
      11:   * 注册一个新定时器
      12:   */
      13:  int uloop_timeout_add(struct uloop_timeout *timeout);
      14:   
      15:  /**
      16:   * 设置定时器超时时间(毫秒),并添加
      17:   */
      18:  int uloop_timeout_set(struct uloop_timeout *timeout, int msecs);
      19:   
      20:  /**
      21:   * 销毁指定定时器
      22:   */
      23:  int uloop_timeout_cancel(struct uloop_timeout *timeout);
      24:   
      25:  /**
      26:   * 获取定时器还剩多长时间超时
      27:   */
      28:  int uloop_timeout_remaining(struct uloop_timeout *timeout);
     
    例子:
       1:  #include <stdio.h>
       2:  #include <stdlib.h>
       3:  #include <string.h>
       4:  #include <sys/types.h>          /* See NOTES */
       5:  #include <sys/socket.h>
       6:  #include <libubox/usock.h>
       7:  #include <libubox/uloop.h>
       8:  int g_fd = -1;
       9:  void send_sock(struct uloop_timeout *t);
      10:   
      11:  struct uloop_timeout tm = {
      12:          .cb = send_sock,
      13:  };
      14:  void send_sock(struct uloop_timeout *t)
      15:  {
      16:      char buf[1024] = {0};
      17:      send(g_fd, "hello world from cilent", strlen("hello world from cilent"), 0);
      18:      if ( recv(g_fd, buf, 1024, 0) > 0) {
      19:              printf("
    recv_buf: %s
    ", buf);
      20:      }
      21:      /* 添加uloop_timeout 实现循环定时 */
      22:      uloop_timeout_set(&tm, 5000);
      23:  }
      24:  int main()
      25:  {
      26:      struct sockaddr cli_addr;
      27:      socklen_t len = sizeof(struct sockaddr);
      28:      int type = USOCK_TCP  | USOCK_NOCLOEXEC | USOCK_IPV4ONLY;
      29:      const char *host = "CarRadio";
      30:      const char *service = "8000";
      31:      char recv_buf[1024] = {0};
      32:      g_fd = usock(type, host, service);    /* create a linker socket*/
      33:      if (g_fd < 0) {
      34:          perror("usock");
      35:          return -1;
      36:      }
      37:      uloop_init();
      38:      /*添加uloop_timeout*/
      39:      uloop_timeout_set(&tm, 5000);
      40:      uloop_run();
      41:      uloop_done();
      42:      
      43:      close(g_fd);
      44:      return 0;
      45:  }
      46:   
     
    五:当前进程的子进程的维护建立一条process链表管理所有的进程id
       1:  struct uloop_process {
       2:      struct list_head list;              
       3:      bool pending;                   
       4:      uloop_process_handler cb;       /** 文件描述符, 调用者初始化 */
       5:      pid_t pid;                                 /** 文件描述符, 调用者初始化 */
       6:  };
       7:  /* 进程退出时回调函数 */
       8:  typedef void (*uloop_process_handler)(struct uloop_process *c, int ret) ;
       9:  /**
      10:   * 注册新进程到事件处理循环
      11:   */
      12:  int uloop_process_add(struct uloop_process *p);
      13:   
      14:  /**
      15:   * 从事件处理循环中销毁指定进程
      16:   */
      17:  int uloop_process_delete(struct uloop_process *p);
    例子:
       1:  #include <stdio.h>
       2:  #include <stdlib.h>
       3:  #include <string.h>
       4:  #include <sys/types.h>          /* See NOTES */
       5:  #include <unistd.h>
       6:  #include <libubox/uloop.h>
       7:   
       8:  struct uloop_process *u_process = NULL;
       9:  /*c: 代表推出的进程, ret:代表推出的状态*/
      10:  void process_exit(struct uloop_process *c, int ret)
      11:  {
      12:      printf("child process exit id[%d], status[%#x]
    ", c->pid, ret);
      13:      free(c);
      14:  }
      15:   
      16:  void child_process(int t)
      17:  {
      18:      printf(" process pid: %d is runing
    ", getpid());
      19:      if (t > 0)
      20:          sleep(t);
      21:      printf("process id[%d] will exit...
    ", getpid());
      22:   
      23:      exit(t);
      24:  }
      25:   
      26:  int main()
      27:  {
      28:      int i;
      29:      pid_t pid;
      30:      uloop_init();
      31:      for (i = 0 ; i < 10; i++) {
      32:          usleep(500);
      33:          pid = fork();
      34:          if (pid == 0) {//子进程
      35:              child_process( (i+1)*10 ); //子进程休眠(i+1)*10s
      36:          }
      37:          else {
      38:              u_process = 
      39:              (struct uloop_process *)malloc(sizeof(struct uloop_process));
      40:              if (NULL == u_process) {
      41:                  perror("malloc");
      42:                  exit(-1);
      43:              }
      44:              u_process->pid = pid;
      45:              u_process->cb = process_exit;
      46:              u_process->pending = false;
      47:              if (uloop_process_add(u_process) < 0) {
      48:                  printf("uloop_process_add failed...
    ");
      49:              }
      50:              printf("success create process pid: %d
    ", pid);
      51:          }
      52:      }
      53:      printf("uloop_runing....
    ");
      54:      uloop_run();
      55:      uloop_done();
      56:      
      57:      return 0;
      58:  }
      59:   
      60:   
  • 相关阅读:
    (转) CS0234: 命名空间“System.Web.Mvc”中不存在类型或命名空间名称“Ajax”(是否缺少程序集引用?)
    服务器修改密码后,发布的网站报“500内部服务器错误”
    关于“/”应用程序中的服务器错误 之解决方案
    (转)根据IP返回对应的位置信息
    (转)C# DateTime格式化大全
    线包字效果
    (转)VS2012网站发布详细步骤
    HTML5 为什么这么火?
    百度地图下拉框搜索建议,并自动添加标注点
    js中检查时间段列表是否有交叉
  • 原文地址:https://www.cnblogs.com/xuyh/p/5647290.html
Copyright © 2011-2022 走看看