zoukankan      html  css  js  c++  java
  • connect设置连接超时

    转自:庖丁解牛

    /**
    * connect_timeout - 带超时的connect(方法中已执行connect)
    * @fd:文件描述符
    * @addr:地址结构体指针
    * @wait_seconds:等待超时秒数,如果为0表示不检测超时
    * 成功返回0.失败返回-1,超时返回-1并且errno = ETIMEDOUT
    * */
    int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    {
        int ret = 0;
        //connect()函数是连接服务器,本来connect会阻塞,但是设置未阻塞之后,
        //客户端仍然会三次握手机制,如果三次握手失败,那么客户端一定无法向文件描述符中写入数据
        //如果连接成功,那么客户端就可以向文件描述符写入数据了,
        //所以交给select监管的文件描述符如果可以写,说明连接成功,不可以写说明连接失败

        //设置当前文件描述符未阻塞--设置非阻塞之后,
        //connect在网络中非常耗时,所以需要设置成非阻塞,如果有读事件,说明可能连接成功
        //这样有利于做超时限制
        if (wait_seconds > 0)
        {
            if (activate_nonblock(fd) == -1)
                return -1;
        }
        ret = connect(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
        if (ret == -1 && errno == EINPROGRESS)
        {
            fd_set writefds;
            FD_ZERO(&writefds);
            FD_SET(fd, &writefds);
            struct timeval timeout;
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, NULL, &writefds, NULL, &timeout);
            } while (ret == -1 && errno == EINTR);
            //ret==-1 不需要处理,正好给ret赋值
            //select()报错,但是此时不能退出当前connect_timeout()函数
            //因为还需要取消文件描述符的非阻塞
            if (ret == 0)
            {
                errno = ETIMEDOUT;
                ret = -1;
            } else if (ret == 1)
            {
                //ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,
                //此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。
                int err = 0;
                socklen_t len = sizeof(err);
                ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
                if (ret == 0 && err != 0)
                {
                    errno = err;
                    ret = -1;
                }
                //说明套接字没有发生错误,成功
            }
        }
        if (wait_seconds > 0)
        {
            if (deactivate_nonblock(fd) == -1)
                return -1;
        }
        return ret;
    }

    ps:有人测试利用getsockopt方式判断连接建立成功与否在linux环境下不可用,如下方式:

    connect(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
    int err = errno;
    if  (err == EISCONN)
        {
             printf("connect finished 111. ");
             ret = 0;
        }

  • 相关阅读:
    oracle数据库 SQL语句、内置函数大全
    oracle数据库常用关键字汇总!
    Java 统计一个项目中src下的所有 .java 文件的代码行数, 注释行数, 空行数
    java用流实现创建文件夹, 文件改名, 文件删除, 文件复制
    深度解析线程工作原理
    重要的几种流:文件流、缓冲流、转换流!
    Java中流的概念和递归算法
    针对集合类容器的归纳总结!
    Comparable、Iterator接口和Collections类的实现方法
    Map接口的一些常用方法
  • 原文地址:https://www.cnblogs.com/qihualin-1024/p/10388359.html
Copyright © 2011-2022 走看看