TCP連接connect等待時長控制的另一種方法


原文地址:http://blog.csdn.net/slin000/article/details/3971644

在TCP網絡應用開發中,作為客戶端的程序經常需要主動連接服務器,這時你就需要建立一個Socket,然后調用connect函數連接到服務器地址。正常情況下,這並沒有什么問題,但當服務器主機不存在的時候,connect函數可能會等待一分多鍾才能返回。如果在主線程中調用connect函數,就會產生長時間無法響應的狀況。

在現代的互聯網硬件環境中,一分鍾的等待有點太長了,我們需要縮短等待時間。

在Linux環境下,可以用alarm調用定時喚醒正在等待的線程,使connect函數從等待中返回,但在Windows下我沒有找到類似的函數。如何讓connect函數返回呢?

經過實驗,找到一個簡單的方法:直接關閉connect函數使用的那個socket套接字,connect函數就會立即返回。這個方法感覺土了點,但確實管用。該方法的工作過程描述如下:
1) 創建socket
2) 啟動定時關閉該socket的線程
3) 調用connect函數連接服務器
4) 取消定時關閉線程的工作
5) 檢查定時關閉線程的關閉操作是否已經執行
6) 檢查connect返回值是否有效

摘錄一段示例代碼如下:

SOCKET CTCPConnector::ConnectTo(int toIp, int toPort,
                                int localIp , int localPort,
                                int timeOut)

{
    SOCKET Socket = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in InetAddr;
    InetAddr.sin_family      = AF_INET;
    InetAddr.sin_addr.s_addr = htonl(localIp);
    InetAddr.sin_port        = htons(localPort);

    if (localIp > 0 && localPort>0)
    {
        if (bind(Socket, (sockaddr *) &InetAddr, sizeof(InetAddr)) < 0)
            return INVALID_SOCKET;
    }

    InetAddr.sin_addr.s_addr = htonl(toIp);
    InetAddr.sin_port        = htons(toPort);

    CTimeOutClose Closer(Socket);  // 這個是超時關閉線程
    if (timeOut > 0)
        Closer.SetTimeOut(timeOut);// 設定超時時長

    int err = connect(Socket, (const sockaddr *)&InetAddr, sizeof(InetAddr));
    if (timeOut >= 0)
    {
        Closer.Cancel();     // 取消超時關閉
        if (Closer.HasDone() // 檢查定時關閉線程的關閉操作是否已經執行
            && err >= 0)     //
        {
            err = -1;         
        }
    }

    if (err < 0) // 檢查connect返回值是否有效
    {            
        return INVALID_SOCKET;
    }

    return Socket;

}

代碼中CTimeOutClose類是啟動關閉線程,等待一段時間后關閉指定的套接字。同時,該類還提供接口,用於取消操作和檢查操作是否已經執行。

雖然該方法需要啟動一個新的線程,但對於大多數的應用來說,主動發起建立TCP連接的量都不會太多,所以對程序的性能並不會產生明顯影響。

(以上代碼可以在我上傳的資源“回城卷軸網絡通訊架構源代碼”中找到,下載地址為:http://download.csdn.net/source/1023342)

作者:蘇林


免責聲明!

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



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