TCP網(wǎng)絡(luò)應(yīng)用開(kāi)發(fā)中,作為客戶端的程序經(jīng)常需要主動(dòng)連接服務(wù)器,這時(shí)你就需要建立一個(gè)Socket,然后調(diào)用connect函數(shù)連接到服務(wù)器地址。正常情況下,這并沒(méi)有什么問(wèn)題,但當(dāng)服務(wù)器主機(jī)不存在的時(shí)候,connect函數(shù)可能會(huì)等待一分多鐘才能返回。如果在主線程中調(diào)用connect函數(shù),就會(huì)產(chǎn)生長(zhǎng)時(shí)間無(wú)法響應(yīng)的狀況。

   在現(xiàn)代的互聯(lián)網(wǎng)硬件TCP連接connect等待時(shí)長(zhǎng)控制的另一種方法環(huán)境中,一分鐘的等待有點(diǎn)太長(zhǎng)了,我們需要縮短等待時(shí)間。

Linux環(huán)境下,可以用alarm調(diào)用定時(shí)喚醒正在等待的線程,使connect函數(shù)從等待中返回,但在Windows下我沒(méi)有找到類(lèi)似的函數(shù)。如何讓connect函數(shù)返回呢?

   經(jīng)過(guò)實(shí)驗(yàn),找到一個(gè)簡(jiǎn)單的方法:直接關(guān)閉connect函數(shù)使用的那個(gè)socket套接字,connect函數(shù)就會(huì)立即返回。這個(gè)方法感覺(jué)土了點(diǎn),但確實(shí)管用。該方法的工作過(guò)程描述如下:

1) 創(chuàng)建socket

2) 啟動(dòng)定時(shí)關(guān)閉該socket的線程

3) 調(diào)用connect函數(shù)連接服務(wù)器

4) 取消定時(shí)關(guān)閉線程的工作

5) 檢查定時(shí)關(guān)閉線程的關(guān)閉操作是否已經(jīng)執(zhí)行

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); //這個(gè)是超時(shí)關(guān)閉線程

       if (timeOut > 0)

              Closer.SetTimeOut(timeOut);// 設(shè)定超時(shí)時(shí)長(zhǎng)

       int err = connect(Socket, (const sockaddr *)&InetAddr, sizeof(InetAddr));

       if (timeOut >= 0)

       {

              Closer.Cancel();//取消超時(shí)關(guān)閉

              if (Closer.HasDone()//檢查定時(shí)關(guān)閉線程的關(guān)閉操作是否已經(jīng)執(zhí)行

&& err >= 0) //

              {

                     err = -1;         }

       }

       if ( err < 0) //檢查connect返回值是否有效

       {            return INVALID_SOCKET;

       }

       return Socket;

}

   代碼中CTimeOutClose類(lèi)是啟動(dòng)關(guān)閉線程,等待一段時(shí)間后關(guān)閉指定的套接字。同時(shí),該類(lèi)還提供接口,用于取消操作和檢查操作是否已經(jīng)執(zhí)行。

   雖然該方法需要啟動(dòng)一個(gè)新的線程,但對(duì)于大多數(shù)的應(yīng)用來(lái)說(shuō),主動(dòng)發(fā)起建立TCP連接的量都不會(huì)太多,所以對(duì)程序的性能并不會(huì)產(chǎn)生明顯影響。

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

作者:蘇林