zoukankan      html  css  js  c++  java
  • 非阻塞connect

    步骤1: 设置非阻塞,启动连接
    实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的。这样调用
    connect 可以立刻返回,根据返回值和 errno 处理三种情况:
    (1) 如果返回 0,表示 connect 成功。
    (2) 如果返回值小于 0, errno 为 EINPROGRESS,  表示连接
          建立已经启动但是尚未完成。这是期望的结果,不是真正的错误。
    (3) 如果返回值小于0,errno 不是 EINPROGRESS,则连接出错了。
     
    步骤2:判断可读和可写
    然后把 sockfd 加入 select 的读写监听集合,通过 select 判断 sockfd
    是否可写,处理三种情况:
    (1) 如果连接建立好了,对方没有数据到达,那么 sockfd 是可写的
    (2) 如果在 select 之前,连接就建立好了,而且对方的数据已到达,
          那么 sockfd 是可读和可写的。
    (3) 如果连接发生错误,sockfd 也是可读和可写的。
    判断 connect 是否成功,就得区别 (2) 和 (3),这两种情况下 sockfd 都是
    可读和可写的,区分的方法是,调用 getsockopt 检查是否出错。
     
    步骤3:使用 getsockopt 函数检查错误
    getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)
    在 sockfd 都是可读和可写的情况下,我们使用 getsockopt 来检查连接
    是否出错。但这里有一个可移植性的问题。
    如果发生错误,getsockopt 源自 Berkeley 的实现将在变量 error 中
    返回错误,getsockopt 本身返回0;然而 Solaris 却让 getsockopt 返回 -1,
    并把错误保存在 errno 变量中。所以在判断是否有错误的时候,要处理
    这两种情况。
     
    代码:
     
    C代码  收藏代码
    int conn_nonb(int sockfd, const struct sockaddr_in *saptr, socklen_t salen, int nsec)  
    {  
        int flags, n, error, code;  
        socklen_t len;  
        fd_set wset;  
        struct timeval tval;  
      
        flags = fcntl(sockfd, F_GETFL, 0);  
        fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);  
      
        error = 0;  
        if ((n == connect(sockfd, saptr, salen)) == 0) {  
            goto done;  
        } else if (n < 0 && errno != EINPROGRESS){  
            return (-1);  
        }  
      
        /* Do whatever we want while the connect is taking place */  
      
        FD_ZERO(&wset);  
        FD_SET(sockfd, &wset);  
        tval.tv_sec = nsec;  
        tval.tv_usec = 0;  
      
        if ((n = select(sockfd+1, NULL, &wset,   
                        NULL, nsec ? &tval : NULL)) == 0) {  
            close(sockfd);  /* timeout */  
            errno = ETIMEDOUT;  
            return (-1);  
        }  
      
        if (FD_ISSET(sockfd, &wset)) {  
            len = sizeof(error);  
            code = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);  
            /* 如果发生错误,Solaris实现的getsockopt返回-1, 
             * 把pending error设置给errno. Berkeley实现的 
             * getsockopt返回0, pending error返回给error.  
             * 我们需要处理这两种情况 */  
            if (code < 0 || error) {  
                close(sockfd);  
                if (error)   
                    errno = error;  
                return (-1);  
            }  
        } else {  
            fprintf(stderr, "select error: sockfd not set");  
            exit(0);  
        }  
      
    done:  
        fcntl(sockfd, F_SETFL, flags);  /* restore file status flags */  
        return (0);  
    }  
  • 相关阅读:
    hdu 1260 Tickets
    hdu 4738 Caocao's Bridges(桥的最小权值+去重)
    找规律
    C语言快速排序
    数组的初始化方法
    C语言选择排序
    副本机制
    安装完Kali的后续操作
    Bool盲注
    Python中的列表
  • 原文地址:https://www.cnblogs.com/foreverstars/p/4758910.html
Copyright © 2011-2022 走看看