zoukankan      html  css  js  c++  java
  • Netty学习之理解epoll

    目录

    epoll原理

    epoll_create

    该函数生成一个epoll专用的文件描述符。

    int epoll_create(int size);

    • size:epoll上能关注的最大文件描述符数

    epoll_ctl

    用于控制某个epoll文件描述符事件,可以注册、修改、删除

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

    • epfd:epoll_create生成的epoll专用的文件描述符

    • op:

      • EPOLL_CTL_ADD 注册

      • EPOLL_CTL_MOD 修改

      • EPOLL_CTL_DEL 删除

    • fd:关联的文件描述符

    • event:告诉内核要监听什么事件

    代码块
    typedef union epoll_data {
       void *ptr;
       int fd;
       uint32_t  u32;
       uint64_t  u64;
    } epoll_data_t;
    ​
    struct epoll_event {
       uint32_t event;
       epoll_data data;
    }
    ​
    events:
    EPOLLIN 读
    EPOLLOUT 写
    EPOLLERR 异常
     

    epoll_wait

    等待IO事件发生

    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

    • epfd:epoll_create生成的epoll专用的文件描述符

    • events:用于回传待处理事件的数组(传出参数)

    • maxevents:告诉内核这个events的大小(events数组的大小肯定是有上限的)

    • timeout:超时时间

      • -1:永久阻塞

      • 0:立即返回

      • >0:超时时间

    代码示例

    #include <ctype.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <sys/epoll.h>int main(int argc, const char* argv[]) 
    {
      if (argc < 2) 
      {
        printf("eg: ./a.out port
    ");
        exit(1);
      }
      struct sockaddr_in serv_addr;
      socklen_t serv_len = sizeof(serv_addr);
      int port = atoi(argv[1]);
    ​
      int lfd = socket(AF_INET, SOCK_STREAM, 0);
      memset(&serv_addr, 0, serv_len);
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
      serv_addr.sin_port = htons(port);
    ​
      bind(lfd, (struct sockaddr*)&serv_addr, serv_len);
      listen(lfd, 36);
      printf("start accept...........
    ");
    ​
      struct sockaddr_in client_addr;
      socklen_t cli_len = sizeof(client_addr);
    ​
        //创建epoll树根节点
      int epfd = epoll_create(2000);
      //初始化epoll树
      struct epoll_evnet ev;
      ev.events = EPOLLIN;
      ev.data.fd = lfd;
      epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
    ​
      struct epoll_event all[2000];
      while (1)
      {
        int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1);
        for (int i =0; i < ret; i++)
        {
          int fd = all[i].data.fd;
          //判断是否有新连接
          if (fd == lfd) {
            //接收连接请求
            int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
            if (cfd == -1) 
            {
              perror("accept error");
              exit(1);
            }
            struct epoll_event temp;
            temp.events = EPOLLIN;
            temp.data.fd = cfd;
            epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp);
            //打印客户端信息
            char ip[64] = {0};
            printf("new client ip: %s, port: %d
    ", inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)), ntohs(client_addr.sin_port));
          } 
          else 
          {
                   //处理已连接的客户端发送过来的数据
            if (!all[i].events & EPOLLIN) 
            {
              continue;
            }
            //读数据
            char buf[1024] = {0};
            int len = recv(fd, buf, sizeof(buf), 0);
            if (len == -1) 
            {
              perror("recv error");
              exit(1);
            }
            else if (len == 0)
            {
              printf("client disconnected
    ");
              //将fd从树上删除
              ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
              if (ret == -1)
              {
                perror("epoll-ctl del error");
                exit(1);
              }
              close(fd);
            }
            else 
            {
              printf("recv buf:%s
    ", buf);
              write(fd, buf, len);
            }
          }
    ​
        }
    ​
      };
      close(lfd);
      return 0;
    }
     

    参考资料

    http://www.man7.org/linux/man-pages/man7/epoll.7.html

    https://www.bilibili.com/video/av44660437/?p=8

    https://www.jianshu.com/p/31cdfd6f5a48

  • 相关阅读:
    DataTable用中使用Compute 实现简单的DataTable数据的统计
    绑定生成一个有树结构的下拉菜单
    Docker--UI管理-----------Portainer安装部署使用
    调整系统的inode数量
    配置Linux服务器从第三方 SMTP 服务器外发邮件
    Jenkins的用户角色权限管理
    shell脚本----MongoDB4.0.21一键安装
    Shell----监控CPU/内存/负载高时的进程
    MySQL配置参数优化
    shell脚本实现---Zabbix5.0快速部署
  • 原文地址:https://www.cnblogs.com/yeyang/p/12580820.html
Copyright © 2011-2022 走看看