zoukankan      html  css  js  c++  java
  • 用select实际非阻塞I/O

    非阻塞read/write

    函数返回0表示可读或可写, -1表示select失败或超时
    select返回0表示超时,-1表示读取失败,1表示可读或可写

    int read_timeout(int fd,unsigned int wait_seconds){
        int ret=0;
        if(wait_seconds > 0){
            fd_set read_fdset;
            struct timeval timeout;
     
            FD_ZERO(&read_fdset);
            FD_SET(fd,&read_fdset);
     
            timeout.tv_sec=wait_seconds;
            timeout.tv_usec=0;
            do{
                ret=select(fd+1,&read_fdset,NULL,NULL,&timeout);
            }while(ret < 0 && errno == EINTR);
     
            if(ret == 0){
                ret = -1;
                errno=ETIMEDOUT;
            }else if(ret == 1)
                ret = 0;
        }
     
        return ret;
    }
     
    int write_timeout(int fd,unsigned int wait_seconds){
        int ret=0;
        if(wait_seconds > 0){
            fd_set write_fdset;
            struct timeval timeout;
     
            FD_ZERO(&write_fdset);
            FD_SET(fd,&write_fdset);
     
            timeout.tv_sec=wait_seconds;
            timeout.tv_usec=0;
            do{
                ret=select(fd+1,NULL,&write_fdset,NULL,&timeout);
            }while(ret < 0 && errno == EINTR);
     
            if(ret == 0){
                ret = -1;
                errno = ETIMEDOUT;
            }else if(ret == 1)
                ret = 0;
        }
        return ret;
    }
    

    非阻塞connect

    非阻塞connect需要辅助函数fcntl
    select返回值分析同read/write, 当connect连接成功或失败,返回的fd都处于可写状态
    所以当select返回1时,需要再次判断connect是否连接成功
    判断方法:
    1.通过getsockopt获取soketfd是否存在错误
    2.通过getpeername判断对方地址是否存在
    3.再次调用connect,判断是否返回错误码EISCONN(连接已建立)

    void activate_nonblock(int fd){
        int ret;
        int flags=fcntl(fd,F_GETFL);
        if(flags == -1)
            err_quit("fcntl");
     
        flags |= O_NONBLOCK;
        ret=fcntl(fd,F_SETFL,flags);
        if(ret == -1)
            err_quit("fcntl");
    }
     
    void deactivate_nonblock(int fd){
        int ret;
        int flags=fcntl(fd,F_GETFL);
        if(flags == -1)
            err_quit("fcntl");
     
        flags &= ~O_NONBLOCK;
        ret=fcntl(fd,F_SETFL,flags);
        if(ret == -1)
            err_quit("fcntl");
    }
     
    int connect_timeout(int fd,struct sockaddr_in *addr,unsigned int wait_seconds){
        int ret;
        socklen_t addrlen=sizeof(struct sockaddr_in);
     
        if(wait_seconds > 0)
            activate_nonblock(fd);
     
        ret=connect(fd,(struct sockaddr *)addr,addrlen);
        if(ret < 0 && errno == EINPROGRESS){
            fd_set connect_fdset;
            struct timeval timeout;
     
            FD_ZERO(&connect_fdset);
            FD_SET(fd,&connect_fdset);
     
            timeout.tv_usec=0;
            timeout.tv_sec=wait_seconds;
            do{
                ret=select(fd+1,NULL,&connect_fdset,NULL,&timeout);
            }while(ret < 0 && errno == EINTR);
     
            if(ret == 0){
                ret = -1;
                errno = ETIMEDOUT;
            }else if(ret < 0)
                return -1;
            else if(ret == 1){
                int err;
                socklen_t socklen=sizeof(err);
                int sockoptret=getsockopt(fd,SOL_SOCKET,SO_ERROR,&err,&socklen);
                if(sockoptret == -1){
                    return -1;
                }else if(err == 0){
                    return 0;
                }else{
                    errno = err;
                    ret = -1;
                }
            }
        }
     
        if(wait_seconds > 0)
            deactivate_nonblock(fd);
     
        return ret;
    }
    

    非阻塞accecpt

    int accept_timeout(int fd,struct sockaddr_in *addr,unsigned int wait_seconds){
        int ret;
        socklen_t addrlen=sizeof(struct sockaddr_in);
     
        if(wait_seconds > 0){
            fd_set accept_fdset;
            struct timeval timeout;
     
            FD_ZERO(&accept_fdset);
            FD_SET(fd,&accept_fdset);
     
            timeout.tv_usec=0;
            timeout.tv_sec=wait_seconds;
            do{
                ret=select(fd+1,&accept_fdset,NULL,NULL,&timeout);
            }while(ret < 0 && errno == EINTR);
     
            if(ret == 0){
                errno = ETIMEDOUT;
                return -1;
            }else if(ret == -1)
                return -1;
        }
     
        if(addr != NULL)
            ret=accept(fd,(struct sockaddr *)addr,&addrlen);
        else
            ret=accept(fd,NULL,NULL);
        if(ret == -1)
            err_quit("accept");
     
        return ret;
    }
    
  • 相关阅读:
    CI框架 -- 核心文件 之 Loader.php(加载器)
    CI框架 -- 核心文件 之 Lang.php(加载语言包)
    CI框架 -- 核心文件 之 Input.php(输入数据处理文件)
    CI框架 -- 核心文件 之 Hooks.php
    CI框架 -- 核心文件 之 Exceptions.php
    CI框架 -- 配置文件config.php
    网站后台发通知页面效果图
    校内通知-Notifications表增加老师,家长,学生发送范围字段
    jqGrid设置指定行的背景色
    SQLServer数据库监控代码
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131894.html
Copyright © 2011-2022 走看看