• I/O多路转接 --- UNIX环境高级编程


         I/O多路转接技术:先构造一张有关描述符的列表,然后调用一个函数,知道这些描述符中的一个已准备好进行I/O时,给函数才返回。在返回时,它告诉进程哪些描述符已准备好可以进行I/O。

            poll、select、pselect这三个函数使我们能够执行I/O多路转接。


    1.select和pselect函数

          I/O多路转接的标准函数,还有一个标准函数poll函数,就这两个
           该函数主要用于终端I/O和网络I/O,但它对其他描述符同样起作用。

          #include <sys/selecet.h>
         int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

        传向select的参数告诉内核,我们所关心的描述符;对于每个描述符我们所关心的状态;愿意等待多长时间;返回值告诉我们,已准备好的的描述符的数量;对于读、写、异常者三个状态中的每一个,哪些描述符已准备好;所以,只用这些返回值,就可调用相应的I/O函数(一般是read和write),并且确知该函数不会阻塞。


     参数意义:
        timeout:它指等待的时间:struct timeval{ long tv_sec; long tv_usec; };
                 timeout = NULL; 永远等待。如果捕捉到一个信号则终端此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到信号一个信号,则返回-1,errno设置为EINTR。
                timeout->tv_sec == 0 && timeout->tv_usec == 0; 完全不等待。测试所有描述符并立即返回。
                timeout->tv_sec != 0 && timeout->tv_usec != 0; 等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回。超时但没有一个描述符准备好则返回0,

      中间3个参数readfds、writefds、exceptfds是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写、=或异常条件的哥哥描述符。每个描述符集存放在一个fs_set数据类型中。这种数据类型为每一可能的描述符保持了一位。

       #include <sys/select.h>
              void FD_CLR(int fd, fd_set *set); 将指定位清掉
              int  FD_ISSET(int fd, fd_set *set); 测试仪指定位是否设置;若fd在集中则返回非0,否则返回0;
                                从select返回时,用其测试该集中的一个给定位是否仍旧设置
              void FD_SET(int fd, fd_set *set); 设置一个指定位
              void FD_ZERO(fd_set *set); 清楚所有位,在声明一个描述符集后,必须先清楚所有位。

       中间的三个参数中任意一个或全部都可是NULL,表示对相应的状态不关心,如果都为空指针,则select提供了较sleep更精确的定时。
      
      第一个参数nfds,“最大描述符加1”。在3个描述符集中,找出最大描述符编号值,然后加1,就是第一个参数的值。第一个参数实际是要检查的描述符的个数


     返回值:
                      -1。表示出错,例如在所指定的描述符都没有准备好时捕捉到一个信号,在此情况下,将不修改其中任何描述符集。
                     0。表示没有描述符准备好。指定的描述符都没有准备好,指定的时间已经超过,则发生这种情况。此时,所有的描述符皆被清0。
                     正返回值。表示已准备好的描述符的个数。是3个描述集中已准备好的描述符数之和,所以同一个描述符已准备好好读和写,返回值中将其记为2.

       对于“已准备好”的意思做一些具体说明:
           若对读集(readfds)中的一个描述符的read操作将不会阻塞,则此描述符准备好了
           若对写集(writefds)中的一个描述符的write操作将不会阻塞,则此描述符准备好了
           若异常状态急(exceptfds)中个一个描述符有一个未决异常状态,则此描述符准备好了


              对于读、写、异常状态,普通文件描述符总是返回准备好。
               一个描述符阻塞与否并不影响select是否阻塞。
              如果在一个描述符上碰到了文件结尾处,则select认为该描述符是可读的,然后调用read,返回0。不要认为到达结尾处,select会只是一个异常状态。


        POSIX.1也定义了一个select的变体,它被称为pselect


           #include <sys/select.h>

           int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);

      除了一下几点外,pselect与select相同:

    2.poll函数(多路I/O转接的标准函数之一,还有一个select)
     与select函数类似,返回值与select相同

     #include <poll.h>
     int poll(struct pollfd *fds, nfds_t nfds, int timeout);
     与select不同,poll不是为每个状态(读、写、异常)构造一个描述符集,而是构造一个pollfd结构体数组。每个数组元素指定一个描述符编号以及对其关心的状态。


     参数:
      第一个参数是结构体数组。struct pollfd{int fd; short events; short revents; };
       每个数组元素的events成员设置的值见表,通过这些值告诉内核我们对描述符关心的是什么。返回时,内核设置revents成员,说明对该描述符已经发生了什么
       【注意】poll函数没有更改events成员,这与select不同,select修改其参数以指示哪一个描述符已准备好。
        


       当一个描述符被挂断(POLLHUP)后,就不能再写向该描述符。但仍可能从该描述符读取到数据

      第二个参数,nfds。fds数组中的元素数由nfds说明

      第三个参数timeout。
                -1.永远等待。返回值情况与select相同
                0.不等待。测试所有描述符并立即返回。
                >0。等待timeout毫秒。返回值情况与select相同。
                  【注】如果系统不提供毫秒级分辨率,则timeout值取整到最近的支持值。


     文件结束与挂断之间的区别。
               如果正从终端输入数据,并键入文件结束字符,POLLIN打开,于是就可读文件结束指示(read返回0)。POLLHUP在revents中没有打开。
               如果正在读调制解调器,并且电话线已挂断,则在revents中将接到POLLHUP通知。


     与select一样。不论一个描述符是否阻塞,都不影响poll是否阻塞。

     


  • 相关阅读:
    《aelf经济和治理白皮书》重磅发布:为DAPP提供治理高效、价值驱动的生态环境
    在线直播: .NET与物联网主流技术探秘 初识IoT!
    2019,.Net开发者的高光时刻
    git stash 切换分支以后 恢复
    redis之简单动态字符串(SDS)
    mysql机制总结
    mac 修改用户权限
    sql注入方法以及防范
    redis学习
    mysql百万数据分页查询速度
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3465090.html
Copyright © 2020-2023  润新知