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

    作用:

    实现I/O的多路复用

    该函数允许进程指示内核等待多个事件中的任何一个发生,并只有在一个或多个事件发生时或经历一段指定的时间后才唤醒它。进程将于select处阻塞,直到被检测的描述符有一个或多个发生了变化。我们可以使用它来监视多个文件描述符的状态变化。

    函数原型:

    int select(int maxfd,fd_set *rdset,fd_set *wrset,   
               fd_set *exset,struct timeval *timeout);  
    

    参数:

    参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

    下面的宏提供了处理这三种描述词组的方式:

    FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
    FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
    FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
    FD_ZERO(fd_set *set);用来清除描述词组set的全部位
    

    参数timeout为结构timeval,用来设置select()的等待时间,其结构定义如下:

    struct timeval  
    {  
        time_t tv_sec;//second  
        time_t tv_usec;//minisecond  
    };  
    

    这个参数有三种可能:

    • 永远等待下去:仅在一个描述符准备号I/O才返回。此时该参数为NULL
    • 等待一段固定时间:在有一个描述符准备好I/O时返回,但不超过由该参数所指向的timeval结构中指定的秒数和微秒数。
    • 不等待:检查描述符后立即返回。这称为轮询(polling)。此时该参数必须指向一个timeval结构,且两个值为0.

    函数返回值

    执行成功: 返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间。

    执行失败: 当有错误时返回-1,错误原因存于errno中,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。错误值可能为:

    • EBADF 文件描述词为无效的或该文件已关闭
    • EINTR 此调用被信号所中断
    • EINVAL 参数n 为负值
    • ENOMEM 核心内存不足

    示例

    这里给出unp中基于select模型的echo服务器。

    int main(int argc, char **argv)
    {
        //服务器初始化
        int i, maxi, maxfd, listenfd, connfd, sockfd;
        int nready, client[FD_SETSIZE];
        ssize_t n;
        fd_set rset, allset;
        char buf[MAXLINE];
        socklen_t clilen;
    
        listenfd = Socket(AF_INET, SOCK_STREAM, 0); //TCP
        struct sockaddr_in servaddr = InitSrvSockaddr(SERV_PORT), cliaddr;
        Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
        Listen(listenfd, LISTENQ);
    
        maxfd = listenfd; //此时listenfd为fd最大值
        maxi = -1;        //index into client array
        for (i = 0; i < FD_SETSIZE; ++i)
            client[i] = -1; //初始化client数组
    
        FD_ZERO(&allset);
        FD_SET(listenfd, &allset); //listenfd 加入allset
    
        for (;;)
        {
            rset = allset;
            nready = Select(maxfd + 1, &rset, NULL, NULL, NULL); //返回状态发生变化的描述符总数
    
            if (FD_ISSET(listenfd, &rset)) //listenfd可用,代表有客户端连接成功
            {
                clilen = sizeof(cliaddr);
                connfd = Accept(listenfd, (SA *)&cliaddr, &clilen);
    
                for (i = 0; i < FD_SETSIZE; ++i) //从开始遍历client数组,找到第一个为-1的位置,将客户的fd保存
                    if (client[i] < 0)           //为-1代表可用
                    {
                        client[i] = connfd;
                        break;
                    }
    
                if (i == FD_SETSIZE) //已满
                    err_quit("too many clients");
    
                FD_SET(connfd, &allset); 
                if (connfd > maxfd)
                    maxfd = connfd;
                if (i > maxi)
                    maxi = i;
                if (--nready <= 0)
                    continue;
            }
            for (i = 0; i <= maxi; ++i)
            {
                if ((sockfd = client[i]) < 2)
                    continue;
                if (FD_ISSET(sockfd, &rset))
                {
                    if ((n = Read(sockfd, buf, MAXLINE)) == 0)
                    {
                        Close(sockfd);
                        FD_CLR(sockfd, &allset);
                        client[i] = -1;
                    }
                    else
                        Writen(sockfd, buf, n);
                    if (--nready <= 0) //就绪描述符数目为0就跳出,避免检查未就绪的描述符
                        break;
                }
            }
        }
    }
    

    参考自:
    http://blog.csdn.net/turkeyzhou/article/details/8609360
    《unix网络编程》

  • 相关阅读:
    Postman初探
    web页面和本地数据对比问题
    Katalon Recorder初探
    Flask入门
    自我实现预言
    gulp 安装 依赖
    maven环境
    加解密 生成 X.509格式,DER编码,后缀名.cer。加密公钥证书
    我的魔法 公式找回中
    gulp 自动ftp至服务器时,处理开发 测试服务器地址问题
  • 原文地址:https://www.cnblogs.com/cknightx/p/7440411.html
Copyright © 2011-2022 走看看