zoukankan      html  css  js  c++  java
  • I/O复用----select

    2018-07-31 (星期二)
    I/O复用:
        一个应用程序通常需要服务一个以上的文件描述符.
        例如stdin,stdout,进程间通信以及若干文件进行I/O,如果不借助线程的话,(线程通常在同一时间无法服务一个以上文件描述符),就是分开每个所要服务的文件描述符,这样做有个问题,就是一旦遇到一个没有准备好的文件描述符,进程就会受阻,可能只受阻几秒,但是用户体验就会大大下降.借助线程,那么进程要维护额外的线程,线程的创建,销毁会增加很多资源.
        因此就出现了I/O复用这个问题.
    运作方式:
        1.I/O复用:当这些文件描述符中有任何一个就绪可进行I/O,请通知我.
        2.休眠:直到有一个或多个文件描述符准备妥当.
        3.唤醒:什么准备就绪了?
        4.处理所有就绪可进行I/O的文件描述符而不收到阻挡.
        5.回到步骤1,从头开始.
    linux提供了三种方案:select,poll,epoll(高级)
    select模型:

    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int select (int n,
            fd_set *readfds,
            fd_set *writefds,
            fd_set *exceptfds,
            struct timeval *timeout);
    
    FD_CLR(int fd, fd_set *set);    将某个文件描述符移除
    
    FD_ISSET(int fd, fd_set *set);    判断fd是否属于分组(可在调用后判断某个文件描述符是否就绪:
            if (FD_ISSET(fd, &readfds))
                /* fd 可供读取不会受到阻挡 */
    
    FD_SET(int fd, fd_set *set);    将fd加入分组中
    
    FD_ZERO(fd_set *set);    讲分组中所有文件描述符移除

    select()系统调用监视的文件描述符分成三个部分,每个部分等待不同的事件:
        readfds分组中的文件描述符用于查看是否读取受阻.
        writefds分组中的文件描述符用于查看是否写入受阻.
        exceptfds分组中的文件描述符用于查看是否有异常或者是否有紧急数据.    

    调用返回所有可用文件描述符.
    参数n等于任何分组中最高编号的文件描述符值+1.
    timeout参数是一个指向timeval结构的指针,该结构的定义如下:

    #include <sys/time.h>
    
    strcut timeval {
        long tv_sec;    /* seconds */
        long tv_usec;    /* microseconds */
    };

    如果此参数不是NULL,那么select() 调用将在tv_sec秒和tv_usec微秒之后返回.(有点强制的意思,就算没有就绪的,也得返回)


    select 当返回为正数时,表示已经准备好的描述符数。返回0时表示超时。发生错误返回-1,并且将errno指定为下面的其中一个值:
        EBADF    分组中提供了一个无效的文件描述符.
        EINTR    等待时捕捉到一个信号,你可以再次调用select().
        EINVAL    参数n是负值或者给定timeout是无效值.
        ENOMEM    内存不足以完成这项要求.

    使用select()去油可以执行的休眠机制
    需要可移植性的休眠机制时,往往采用select(), 方法是提供非NULL值的timeout参数,但是三个分组参数全部为NULL:

    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 500;
    /* 休眠500毫秒 */
    select (0, NULL, NULL, NULL, &tv);

    当然,Linux也会为高分辨率休眠机制提供接口.

    小例子:

    #include <stdio.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #define TIMEOUT 5    /*select的等待时间,以秒为单位 */
    #define BUF_LEN 1024     /* 读取缓冲区,以字节为单位 */
    
    int main(void) {
        struct timeval tv;
        fd_set readfds;
        int ret;
        
        /* 等候stdin的输入数据 */
        FD_ZERO(&readfds);
        FD_SET(STDIN_FILENO, &readfds);
    
        /* 等候5秒的时间 */
        tv.tv_sec = TIMEOUT;
        tv.tv_usec = 0;
    
        /* 好了,开始提供服务! */
        ret = select (STDIN_FILENO + 1,
                &readfds,
                NULL,
                NULL,
                &tv);
        if (ret == -1) {
            perror ("select");
            return 1;
        } else if (!ret) {
            printf("%d seconds elapsed.
    ", TIMEOUT);
            return 0;
        }
    
        /*
         * 我们的文件描述符可供读取了吗?
         * (肯定可以,因此他是我们所提供的唯一fd,
         * 而且次调用会返回非零值,但是我们还想有自己一默)
         */
        if (FD_ISSET(STDIN_FILENO, &readfds)) {
            char buf[BUF_LEN+1];
            int len;
            /* 保证不会遭到阻挡 */
            len = read (STDIN_FILENO, buf, BUF_LEN);
            if (len == -1) {
                perror ("read");
                return -1;
            } 
            if (len) {
                buf[len] = '';
                printf ("read: %s
    ", buf);
                return 0;
            }
        }
        fprintf (stderr, "This should not happen!
    ");
        return 1;
    }
  • 相关阅读:
    linux常见的编码转换
    linux sort的用法
    转--11个失败之后
    shell入门
    迟到
    必须要回答的问题
    【转载】个人开发者要掌握的时间规划建议
    Unity 碰撞检测 OnTriggerEnter 入门
    浅谈BUFF设计
    随机掉宝,对玩家来讲真的随机吗?
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/9399067.html
Copyright © 2011-2022 走看看