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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM