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.\n");
         ret = 0;
    }


免責聲明!

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



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