zoukankan      html  css  js  c++  java
  • 总结一下三个io复用函数

    1.select  

    int select(int nfds, fd_set *readfds, fd_set *writefds,
                      fd_set *exceptfds, struct timeval *timeout);

    1)nfds为被监听文件描述符的总数,通常为个数+1

    2)struct fd_set由定义来看__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];包含一个整形数组,其中每个位代表着一个文件描述符,这代表了读文件描述符的集合。需要注意的是,监听文件描述符的最大数由fd_setsize决定,其最大值是1024。

    3)代表写文件描述符的集合。

    4)异常文件描述符的集合。

    5)struct timeout结构

    struct timeval
      {
        __time_t tv_sec;        /* Seconds.  */
        __suseconds_t tv_usec;    /* Microseconds.  */
      };

    第一个成员为秒,第二个成员为微妙,可见提供到微妙的支持。如果该结构指定为null,则一直阻塞此函数直到有事件发生。

    6)return:成功返回0,失败返回-1并置errno。

    7)提供以下宏函数代替位的繁琐操作

    #define    FD_SET(fd, fdsetp)    __FD_SET (fd, fdsetp)  //将文件描述符置位,相当于加入到该集合当中。
    #define    FD_CLR(fd, fdsetp)    __FD_CLR (fd, fdsetp)  //清除该文件描述符上的位,相当于从集合中取出。
    #define    FD_ISSET(fd, fdsetp)    __FD_ISSET (fd, fdsetp)  //判断文件描述符是否在其中
    #define    FD_ZERO(fdsetp)        __FD_ZERO (fdsetp)  //将该文件描述符清零。

    8)更要注意的是,在向内核注册事件,通知完该事件之后,一定要重新注册一遍,即fd_set需要重新FD_SET进文件描述符。因为只能监听3个事件,读写异常,所以限制较多。

    2.poll

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

    1)struct pollfd结构

                   int   fd;         /* file descriptor */
                   short events;     /* requested events */
                   short revents;    /* returned events */
               };

      1.1)events是需要在该文件描述符上监听的事件,通常是下列宏的位掩码:

                  POLLIN               //该文件描述符有数据可读
                 There is data to read. POLLPRI        //紧急数据(oob) There is urgent data to read (e.g., out-of-band data on TCP socket; pseudoterminal master in packet mode has seen state change in slave). POLLOUT        //写的缓冲区现在不阻塞了,可以该描述符写东西 Writing now will not block. POLLRDHUP (since Linux 2.6.17)    //仅linux支持,文件描述符对方关闭了写,或者关闭了连接,这个很有必要知道 Stream socket peer closed connection, or shut down writ‐ ing half of connection. The _GNU_SOURCE feature test macro must be defined (before including any header files) in order to obtain this definition. POLLERR        //错误事件 Error condition (output only). POLLHUP        //挂起 Hang up (output only). POLLNVAL      //文件描述符不有效 Invalid request: fd not open (output only).
      如果定义了_XOPEN_SOURCE,那么还有如下的宏:

              POLLRDNORM       //normal,正常的可读数据,相当与pollin
                  Equivalent to POLLIN.

              POLLRDBAND    //linux中不可用
                           Priority band data can be read (generally unused onLinux).

              POLLWRNORM    //相当于pollout
                           Equivalent to POLLOUT.

              POLLWRBAND    //更高优先级的数据可写
                  Priority data may be written.

      1.2)内核返回的事件。

    2)文件描述符的总数,typeof unsigned long int nfds_t

    3)监听时间,指定为0立即返回,指定为-1则一直阻塞直到所监听描述符上有事件发生。

    4)return:正常返回0,异常返回-1并置errno

    3.epoll

      //需要如下的一组函数来完成     
        * epoll_create(2) creates an epoll instance and returns a file descriptor referring to that instance. (The more recent epoll_cre‐ ate1(2) extends the functionality of epoll_create(2).) * Interest in particular file descriptors is then registered via     epoll_ctl(2). The set of file descriptors currently registered on an epoll instance is sometimes called an epoll set. * epoll_wait(2) waits for I/O events, blocking the calling thread if no events are currently available.

    1)向内核注册事件表,参数为需要监听的文件描述符的个数。

    2)extern int epoll_ctl (int __epfd, int __op, int __fd,struct epoll_event *__event) __THROW;  //类似于fcntl函数

      2.1)指定的epollfd事件表的描述符

      2.2)op操作的类型,有如下的宏可选

    #define EPOLL_CTL_ADD 1    /* Add a file descriptor to the interface.  */       //添加
    #define EPOLL_CTL_DEL 2    /* Remove a file descriptor from the interface.  */   //删除
    #define EPOLL_CTL_MOD 3    /* Change file descriptor epoll_event structure.  */  //修改

      2.3)需要监听的文件描述符

      2.4)struct epoll_event结构

    struct epoll_event
    {
      uint32_t events;    /* Epoll events */
      epoll_data_t data;    /* User data variable */
    } __EPOLL_PACKED;

        2.4.1)events为需要监听事件的位掩码,如下所示

    enum EPOLL_EVENTS
      {
        EPOLLIN = 0x001,          //有数据可读
    #define EPOLLIN EPOLLIN
        EPOLLPRI = 0x002,    //有紧急数据(oob)可读
    #define EPOLLPRI EPOLLPRI
        EPOLLOUT = 0x004,    //该描述符有缓冲区可供写
    #define EPOLLOUT EPOLLOUT
        EPOLLRDNORM = 0x040,      //normal
    #define EPOLLRDNORM EPOLLRDNORM
        EPOLLRDBAND = 0x080,        //优先级数据可读
    #define EPOLLRDBAND EPOLLRDBAND
        EPOLLWRNORM = 0x100,      //normal write
    #define EPOLLWRNORM EPOLLWRNORM
        EPOLLWRBAND = 0x200,      //优先级数据可写
    #define EPOLLWRBAND EPOLLWRBAND
        EPOLLMSG = 0x400,        //没了解过
    #define EPOLLMSG EPOLLMSG
        EPOLLERR = 0x008,
    #define EPOLLERR EPOLLERR       //错误消息
        EPOLLHUP = 0x010,
    #define EPOLLHUP EPOLLHUP    //挂起
        EPOLLRDHUP = 0x2000,
    #define EPOLLRDHUP EPOLLRDHUP    //描述符的对方关闭了写操作,或者关闭了连接
        EPOLLWAKEUP = 1u << 29,
    #define EPOLLWAKEUP EPOLLWAKEUP    //没了解
        EPOLLONESHOT = 1u << 30,
    #define EPOLLONESHOT EPOLLONESHOT  //在任意时刻仅可以触发一个可读可写异常事件,常用与多线程
        EPOLLET = 1u << 31
    #define EPOLLET EPOLLET   //使用et方式工作,默认lt
      };

        2.4.2)

    typedef union epoll_data
    {
      void *ptr;
      int fd;
      uint32_t u32;
      uint64_t u64;
    } epoll_data_t;

      可以看出是一个union,ptr指的是数据地址,fd指的是文件描述符,通常我们使用文件描述符。

        2.4.3)关于et(边缘敏感)与lt(水平敏感):lt模式:通知之后可不处理。et:通知之后必须处理,且对该事件仅通知一次

      2.5)成功返回0,失败返回-1

    3)

    extern int epoll_wait (int __epfd, struct epoll_event *__events,
                   int __maxevents, int __timeout);

      3.1)指定的epollfd

      3.2)触发事件的数组集合

      3.3)需要监听的最大描述符数量

      3.4)timeout,-1则一直阻塞直到有事件发生。

      3.5)返回有发生事件的文件描述符个数。

    4)通常我们要往一个epollfd添加文件描述符的函数接口可以这么写:

    void addfd(int epollfd,int fd)
    {
        struct epoll_event event;
        event.data.fd=fd;
        event.events=EPOLLIN|EPOLLET;
        epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);
        setnonblocking(fd);
    }

    5)通常设置一个文件描述符为非阻塞可以这么写:

    int setnonblocking(int fd)
    {
        int old_option=fcntl(fd,F_GETFL);
        int new_option=old_option|O_NONBLOCK;
        fcntl(fd,F_SETFL,new_option);
        return old_option;
    }

    4.详情请看man或者源码

  • 相关阅读:
    Linux常用命令(5)--SSH访问远程服务器、SCP服务器间文件拷贝
    【转载】善用工具(1)--Mac版UltraEdit编辑器破解方法
    Linux常用命令(4)--善用"help"、"man在线帮助文档",轻松搞定系统命令
    Linux常用命令(3)--文件管理(查看文件大小权限信息、修改文件所属用户和操作权限、压缩解压文件)
    Linux常用命令(2)--vi (vim)文本编辑工具
    Linux常用命令(1)--用户管理(添加用户、修改密码、授予root权限)
    30分钟掌握ES6/ES2015核心内容(下)
    30分钟掌握ES6/ES2015核心内容(上)
    99%的人都理解错了HTTP中GET与POST的区别
    js中const,var,let区别
  • 原文地址:https://www.cnblogs.com/manch1n/p/10555815.html
Copyright © 2011-2022 走看看