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;
    }
    
  • 相关阅读:
    解决IE9下JQuery的ajax失效的问题
    npm更新到最新版本的方法
    animate.css配合wow.min.js实现各种页面滚动效果
    Bootstrap导航点击菜单跳转与点击缩放菜单折叠按钮缓冲效果插件jquery.singlePageNav.min.js
    对json对象进行截取并按照某关键字进行排序
    巧用 position:absolute
    EasyUI Datagrid 分页
    Cssreset
    杂记
    for循环遍历json(附习题及答案)
  • 原文地址:https://www.cnblogs.com/cfans1993/p/6131894.html
Copyright © 2011-2022 走看看