當前位置:編程學習大全網 - 源碼下載 - 如何設置connect超時時間

如何設置connect超時時間

1.首先將標誌位設為Non-blocking模式,準備在非阻塞模式下調用connect函數

2.調用connect,正常情況下,因為TCP三次握手需要壹些時間;而非阻塞調用只要不能立即完成就會返回錯誤,所以這裏會返回EINPROGRESS,表示在建立連接但還沒有完成。

3.在讀套接口描述符集(fd_set rset)和寫套接口描述符集(fd_set

wset)中將當前套接口置位(用FD_ZERO()、FD_SET()宏),並設置好超時時間(struct

timeval *timeout)

4.調用select( socket, &rset, &wset, NULL, timeout )

返回0表示connect超時

如果妳設置的超時時間大於75秒就沒有必要這樣做了,因為內核中對connect有超時限制就是75秒。

網絡編程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口編程中,提到超時的概念,我們壹下子就能想到3個:發送超時,接收超時,以及select超時(註:

select

函數並不是只用於套接口的,但是套接口編程中用的比較多),在connect到目標主機的時候,這個超時是不由我們來設置的。不過正常情況下這個超時都很

長,並且connect又是壹個阻塞方法,壹個主機不能連接,等著connect返回還能忍受,妳的程序要是要試圖連接多個主機,恐怕遇到多個不能連接的

主機的時候,會塞得妳受不了的。我也廢話少說,先說說我的方法,如果妳覺得妳已掌握這種方法,妳就不用再看下去了,如果妳還不了解,我願意與妳分享。本文

是已在Linux下的程序為例子,不過拿到Windows中方法也是壹樣,無非是換幾個函數名字罷了。

Linux中要給connect設置超時,應該是有兩種方法的。壹種是該系統的壹些參數,這個方法我不講,因為我講不清楚:P,它也不是編程實現的。另外壹種方法就是變相的實現connect的超時,我要講的就是這個方法,原理上是這樣的:

1.建立socket

2.將該socket設置為非阻塞模式

3.調用connect()

4.使用select()檢查該socket描述符是否可寫(註意,是可寫)

5.根據select()返回的結果判斷connect()結果

6.將socket設置為阻塞模式(如果妳的程序不需要用阻塞模式的,這步就省了,不過壹般情況下都是用阻塞模式的,這樣也容易管理)

如果妳對網絡編程很熟悉的話,其實我壹說出這個過程妳就知道怎麽寫妳的程序了,下面給出我寫的壹段程序,僅供參考。

/******************************

* Time out for connect()

* Write by Kerl W

******************************/

#include

#include

#define TIME_OUT_TIME 20 //connect超時時間20秒

int main(int argc , char **argv)

{

………………

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if(sockfd < 0) exit(1);

struct sockaddr_in serv_addr;

………//以服務器地址填充結構serv_addr

int error=-1, len;

len = sizeof(int);

timeval tm;

fd_set set;

unsigned long ul = 1;

ioctl(sockfd, FIONBIO, &ul); //設置為非阻塞模式

bool ret = false;

if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ==

-1)

{

tm.tv_set = TIME_OUT_TIME;

tm.tv_uset = 0;

FD_ZERO(&set);

FD_SET(sockfd, &set);

if( select(sockfd+1, NULL, &set, NULL, &tm) > 0)

{

getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);

if(error == 0) ret = true;

else ret = false;

} else ret = false;

}

else ret = true;

ul = 0;

ioctl(sockfd, FIONBIO, &ul); //設置為阻塞模式

if(!ret)

{

close( sockfd );

fprintf(stderr , "Cannot Connect the server!n");

return;

}

fprintf( stderr , "Connected!n");

//下面還可以進行發包收包操作

……………

}

以上代碼片段,僅供參考,也是為初學者提供壹些提示,主要用到的幾個函數,select,

ioctl,

getsockopt都可以找到相關資料,具體用法我這裏就不贅述了,妳只需要在linux中輕輕的敲壹個man

<函數名>就能夠看到它的用法。

此外我需要說明的幾點是,雖然我們用ioctl把套接口設置為非阻塞模式,不過select本身是阻塞的,阻塞的時間就是其超時的時間由調用select

時候的最後壹個參數timeval類型的變量指針指向的timeval結構變量來決定的,timeval結構由壹個表示秒數的和壹個表示微秒數(long

類型)的成員組成,壹般我們設置了秒數就行了,把微妙數設為0(註:1秒等於100萬微秒)。而select函數另壹個值得壹提的參數就是上面我們用到的

fd_set類型的變量指針。調用之前,這個變量裏面存了要用select來檢查的描述符,調用之後,針對上面的程序這裏面是可寫的描述符,我們可以用宏

FD_ISSET來檢查某個描述符是否在其中。由於我這裏只有壹個套接口描述符,我就沒有使用FD_ISSET宏來檢查調用select之後這個

sockfd是否在set裏面,其實是需要加上這個判斷的。不過我用了getsockopt來檢查,這樣才可以判斷出這個套接口是否是真的連接上了,因為

我們只是變相的用select來檢查它是否連接上了,實際上select檢查的是它是否可寫,而對於可寫,是針對以下三種條件任壹條件滿足時都表示可寫

的:

1)套接口發送緩沖區中的可用控件字節數大於等於套接口發送緩沖區低潮限度的當前值,且或者i)套接口已連接,或者ii)套接口不要求連接(UDP方式的)

2)連接的寫這壹半關閉。

3)有壹個套接口錯誤待處理。

這樣,我們就需要用getsockopt函數來獲取套接口目前的壹些信息來判斷是否真的是連接上了,沒有連接上的時候還能給出發生了什麽錯誤,當然我程序中並沒有標出那麽多狀態,只是簡單的表示可連接/不可連接。

下面我來談談對這個程序測試的結果。我針對3種情形做了測試:

1. 目標機器網絡正常的情況

可以連接到目標主機,並能成功以阻塞方式進行發包收包作業。

2. 目標機器網絡斷開的情況

在等待設置的超時時間(上面的程序中為20秒)後,顯示目標主機不能連接。

3. 程序運行前斷開目標機器網絡,超時時間內,恢復目標機器的網絡

在恢復目標主機網絡連接之前,程序壹只等待,恢復目標主機後,程序顯示連接目標主機成功,並能成功以阻塞方式進行發包收包作業。

上各種情況的測試結果表明,這種設置connect超時的方法是完全可行的。我自己是把這種設置了超時的connect封裝到了自己的類庫,用在壹套監控

系統中,到目前為止,運行還算正常。這種編程實現的connect超時比起修改系統參數的那種方法的有點就在於它只用於妳的程序之中而不影響系統。

connect非阻塞套接口時候,壹般使用在以下幾種情況:

1.三路握手需要時間,這個要視具體的網絡情況而定。當然也有可能失敗。在三路握手的時候我們並不需要在原地等待三路握手的完成,可以用這些時間來

完成其它事情,然後當這些事情完成後,再去檢測連接是否建立(也就是三路握手是否完成)。

2.可以用這種技術來同時建立多個連接。(WEB瀏覽器中很常用)。

3.connect超時需要很長時間才會通知,如果我們認為超過0.1秒以後就算超時(不管它是不是真的超時),這是就可以使用非阻塞式I/O結合

select來完成。

當采用非阻塞式I/O來使用connect時候,要判斷壹個連接是否建立則比較復雜,需要按照以下幾個步驟來完成

1.即使是使用非阻塞式的connect操作,connect依然可能正確返回,也就是說非阻塞的connect

也有可能三路連接完成後返回,這種情況壹般發生在服務器和主機在同壹個機器上,所以第壹步要判斷connect是否正確返回,如果正確返回則請做正確返回

的處理,否則進入步驟2

2.設置fd_set,(如果沒看明白,請先看select函數介紹),讓select函數同時監聽套接字的讀寫2個屬性,如果既可讀也可寫則進入

步驟3,如果可寫但不可讀進入步驟4.

3.如果到達這步,我們需要調用getsockopt進壹步判斷。這裏涉及到壹個移植問題,getsockopt如果發生錯誤,

源自Berkeley的實現會返回0,如果是solaris,則會返回-1。建議是2個都處理(如果看不明白請先看getsockopt函數,套接口選

項)。根據getsockopt通過參數返回的erron的值,如果值為0則表示鏈接建立完成,如果不為0, 則說明鏈接建立沒有完成。

4.如果能到達這裏,則說明連接建立完成。

最後,即使最後妳得出鏈接沒有建立完成,也只是說:可能三路握手的過程還是沒有完成。

  • 上一篇:企業應該如何建設響應式網站
  • 下一篇:怎麽用swot模式和五力競爭模式分析南昌工程學院。。。。。?
  • copyright 2024編程學習大全網