Linux:select、poll 和 epoll 简述

Linux:select、poll 和 epoll 简述

备注:三种模型的对比参考:点这里

select

  • 函数原型

    int select( int maxfdp, fd_set * readfds, fd_set * writefds, fd_set * errorfds, struct timeval * timeout);

  • 参数

    • maxfdp:数值为三个集(readfdswritefdserrorfds)中最大的描述符的值+1
    • readfds:用来检查可读性的一组文件描述字,可为 NULL
    • writefds:用来检查可写性的一组文件描述字,可为 NULL
    • errorfds:用来检查是否有异常条件出现的文件描述字,可为 NULL
    • timeout:计时设置,超时则返回值为0(注意:超时之后会将timeout初始化为0)
      • timeout = NULL 时,无限阻塞,直到描述符状态改变或者收到信号,轮询返回对应值
      • timeout.tv_sec = 0 且 timeout.tv_usec = 0 时,无限轮询,每次都返回对应值(需注意)
      • 其他,等到一定时间后超时,轮询检查描述符状态,返回对应值
  • 返回值

    • 成功:返回检测到的事件个数(可为0)
    • 失败:返回 -1
  • 头文件

    #include <sys/select.h>

  • 相关函数

    • FD_ZERO (fd_set * fdset); //置0文件描述符集fdset
    • FD_SET (int fd, fd_set * fdset); //将 fd 放入 fdset 集
    • FD_CLR (int fd, fd_set * fdset); //从 fdset 集删除 fd
    • FD_ISSET (int fd, fd_set * fdset); //测试文件描述符fd是否在fdset集
  • man 中的示例

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int
    main(void)
    {
        fd_set rfds;
        struct timeval tv;
        int retval;
    
        /* Watch stdin (fd 0) to see when it has input. */
        FD_ZERO(&rfds);
        FD_SET(0, &rfds);
    
        /* Wait up to five seconds. */
        tv.tv_sec = 5;
        tv.tv_usec = 0;
    
        retval = select(1, &rfds, NULL, NULL, &tv);
        /* Don't rely on the value of tv now! */
    
        if (retval == -1)
            perror("select()");
        else if (retval)
            printf("Data is available now.\n");
            /* FD_ISSET(0, &rfds) will be true. */
        else
            printf("No data within five seconds.\n");
    
        exit(EXIT_SUCCESS);
    }
    

poll

  • 函数原型

    int poll(struct pollfd* fds, nfds_t nfds, int timeout);

  • 参数

    • fds,I/O描述符集
    • nfds,待检测I/O数量
    • timeout,计时设置
  • 返回值

    • 成功:返回检测到的事件个数(可为0)
    • 失败:返回 -1
  • 头文件

    #include <poll.h>

  • 相关结构体

    • struct pollfd
      struct pollfd {
      	int fd;        // 文件描述符 
      	short events;  // 等待事件
      	short revents; // 发生事件
      };
      
  • 事件(events)

    含义
    POLLIN有数据可
    POLLPRI有紧急数据可
    POLLOUT数据可
    OLLRDHUP流式套接字半关闭
    POLLERR错误事件
    POLLHUP挂起事件
    POLLNVAL描述符非法
    POLLRDNORM有普通数据可
    POLLRDBAND有优先数据可
    POLLWRNORM普通数据可
    POLLWRBAND优先数据可

epoll

  • 相关函数

    • epoll_create
    • epoll_create1
    • epoll_ctl
    • epoll_wait
  • 相关函数详解

    • int epoll_create(int size);
      • 参数
        • size:监测的描述符最大数量
      • 返回值
        • 正值表示的一个 epoll 文件描述符

    • int epoll_create1(int flags);
      • 参数
        • flags:可为 0 或者 EPOLL_CLOEXEC(详情参考该博客
      • 返回值
        • 正值表示的一个 epoll 文件描述符

    • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
      • 参数
        • epfdepoll 文件描述符(epoll_create() 的返回值)
        • op:表示动作
          • EPOLL_CTL_ADD:注册 fdepfd
          • EPOLL_CTL_MOD:修改监听事件;
          • EPOLL_CTL_DEL:从 epfd 中删除 fd
        • fd:需要监听的fd
        • event:告诉内核需要监听什么事件
      • 返回值
        • 成功:返回 0
        • 失败:返回 -1
      • 相关结构体
        struct epoll_event {
          __uint32_t events;  //事件
           epoll_data_t data; 
        };
        typedef union epoll_data {
           void        *ptr;
           int          fd;	//文件描述符
           uint32_t     u32;
           uint64_t     u64;
        } epoll_data_t;		 
        

    • int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int
      timeout);
      • 参数
        • epfdepoll 文件描述符( epoll_create() 的返回值)
        • events:用来从内核得到事件的集合
        • maxevents:表示每次能处理的最大事件数,告之内核 events 大小,maxevents 的值不能大于创建 epoll_create()size
        • timeout:计时设置
          • 毫秒级
          • 0:会立即返回
          • -1:永久阻塞直到事件产生
      • 返回值
        • 成功:返回需要处理的事件个数(可为0)
        • 失败:返回 -1
      • 备注
        • 使用时直接遍历 0至返回值 即可(由于注册到了 epfd 中,因此将 struct epoll_event 交于 epoll 管理,将发生事件的 struct epoll_event 提到 events 集的首部)
      • man 中的示例
        #define MAX_EVENTS 10
        struct epoll_event ev, events[MAX_EVENTS];
        int listen_sock, conn_sock, nfds, epollfd;
        
        /* Set up listening socket, 'listen_sock' (socket(),
           bind(), listen()) */
        
        epollfd = epoll_create(10);
        if (epollfd == -1) {
            perror("epoll_create");
            exit(EXIT_FAILURE);
        }
        
        ev.events = EPOLLIN;
        ev.data.fd = listen_sock;
        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
            perror("epoll_ctl: listen_sock");
            exit(EXIT_FAILURE);
        }
        
        for (;;) {
            nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
            if (nfds == -1) {
                perror("epoll_pwait");
                exit(EXIT_FAILURE);
            }
        
            for (n = 0; n < nfds; ++n) {
                if (events[n].data.fd == listen_sock) {
                    conn_sock = accept(listen_sock,
                                    (struct sockaddr *) &local, &addrlen);
                    if (conn_sock == -1) {
                        perror("accept");
                        exit(EXIT_FAILURE);
                    }
                    setnonblocking(conn_sock);
                    ev.events = EPOLLIN | EPOLLET;
                    ev.data.fd = conn_sock;
                    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                                &ev) == -1) {
                        perror("epoll_ctl: conn_sock");
                        exit(EXIT_FAILURE);
                    }
                } else {
                    do_use_fd(events[n].data.fd);
                }
            }
        }
        
  • 头文件

    #include <sys/epoll.h>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值