• socket使用非阻塞connect


    在使用tcp的connect调用时,默认是使用阻塞方式,当服务器当前不可用时,connect会等待(内部在重试?)直到超时时间到达,而这个超时时间是系统内核规定的,不能使用setSocketOpt来设置。

    在碰到服务器不可用,上层逻辑进行重试时,如果超时时间过长,会产生卡死的感觉,用户体验也不佳,所以需要控制connect的超时时间。

    参考网络上的资料,这里使用select。实现方式是:将socket设置为非阻塞方式,使用select来轮询socket,在select里指定超时时间,根据socket来判断连接状态。最后恢复socket的阻塞方式。

    代码如下(linux):

    int connect_with_timeout(int socket, const struct sockaddr *address, socklen_t address_len, int time_out)
    {
        int flag, old_flag;
        old_flag = flag = fcntl(socket, F_GETFL, 0);
        flag |= O_NONBLOCK;
        fcntl(socket, F_SETFL, flag);
    
        int ret = -1;
        ret = ::connect(socket, (struct sockaddr*)address, address_len);
        if (ret != 0) {
            if (errno != EINPROGRESS) {
                LOG("connect failed,err(%d)", errno);
            } else {
                struct timeval tm;
                tm.tv_sec = time_out;
                tm.tv_usec = 0;
                fd_set set,rset;
                FD_ZERO(&set);
                FD_ZERO(&rset);
                FD_SET(socket, &set);
                FD_SET(socket, &rset);
    
                int res;
                res = ::select(socket+1, &rset, &set, NULL, &tm);
                if (res < 0) {
                    LOG("select:network error in connect.errno:%d", errno);
                } else if(res == 0) {
                    LOG("select:connect timeout.errno:%d", errno);
                } else if (res == 1) {
                    if (FD_ISSET(socket, &set)) {
                        LOG("select success");
                        ret = 0;
                    }
                } else {
                    LOG("other error when select: %s", strerror(errno));
                }
            }
        }
    
        fcntl(socket, F_SETFL, old_flag);
    
        return ret;
    }

    ::connect在非阻塞模式下会立即返回,如果没有其他错误,返回值等于0。

    当::connect不能立即建立连接时,会返回EINPROGRESS,表示正在连接的过程中,这时可以使用select去轮询套接口,而select超时时间由参数指定 。

    select返回值小于0,表明connect出错;等于0,表明connect超时;等于1,并且套接口的状态是可写,则表明connect已经成功建立。

    最后恢复socket的阻塞属性。

    参考:

    http://olive101.blog.163.com/blog/static/2051263201011221915696/

  • 相关阅读:
    c&c++中的宏
    cmake教程
    什么是Grunt
    npm-install camo
    在node.js中建立你的第一个HTTp服务器
    highChart数据动态更新
    css:before和after中的content属性
    清除float浮动三种方式
    中文标准web字体
    网站桌面端和手机端不同url的设置
  • 原文地址:https://www.cnblogs.com/bugchecker/p/using_nonblock_connect_in_tcp_connection.html
Copyright © 2020-2023  润新知