非阻塞方式connect程式設計

2022-05-09 06:00:12 字數 3995 閱讀 8298

①setsockopt()函式使用詳解:

②setsockopt :so_linger 選項設定:

③time_wait狀態的作用:

在學習linux下c網路程式設計時,標準的c/s架構的網路體系模式時,沒有注意connect的非阻塞模式,最近看專案**時,發現原來connect非阻塞模式還有這麼大的作用。但從程式客戶端的角度,優化大量客戶端連線伺服器的效能。讓我突然想起曾經面試時的問題,tcp三次握手與四次揮手與你寫的程式有什麼關係。現在就知道了。

關於:tcp三次握手與四次揮手,請看我之前的部落格。

說明:由於程式用select等待連線完成,可以設定乙個select等待時間限制,從而縮短connect超時時間。多數實現中,connect的超時時間在75秒到幾分鐘之間。有時程式希望在等待一定時間內結束,使用非阻塞connect可以防止阻塞75秒,在多執行緒網路程式設計中,尤其必要。 例如有乙個通過建立執行緒與其他主機進行socket通訊的應用程式,如果建立的執行緒使用阻塞connect與遠端通訊,當有幾百個執行緒併發的時候,由於網路延遲而全部阻塞,阻塞的執行緒不會釋放系統的資源,同一時刻阻塞執行緒超過一定數量時候,系統就不再允許建立新的執行緒(每個程序由於程序空間的原因能產生的執行緒有限),如果使用非阻塞的connect,連線失敗使用select等待很短時間,如果還沒有連線後,執行緒立刻結束釋放資源,防止大量執行緒阻塞而使程式崩潰。

int tcp_connect(char *host, int

port)

; memset ((

char *)&rsock,0,sizeof

(rsock));

if ((hostinfo = gethostbyname(host)) ==null)

//步驟一:socket

sock = socket(af_inet, sock_stream, 0

);

if (sock == -1

)

//步驟二:填充

addp = (struct in_addr *)*(hostinfo->h_addr_list);

rsock.sin_addr = *addp;

rsock.sin_family =af_inet;

rsock.sin_port =htons(port);

int ret = 0, error = -1, slen = sizeof(int

); timeval tm;

fd_set

set;

unsigned

long ul = 1

; ioctl(sock, fionbio, &ul); //

設定為非阻塞模式

//步驟三:connect,此時socket設定為非阻塞,connect呼叫後,無論連線是否建立立即返回-1,

if (connect(sock, (struct sockaddr *)(&rsock), sizeof(rsock)) == -1

)

else

else

}else}}

else

ul = 0

; ioctl(sock, fionbio, &ul); //

設定為阻塞模式

//ret =1:表示正常建立連線

if (!ret)

//linger :徘徊的意思。so_linger:表示經歷time_wait階段,且時間是stlinger中第二個引數指定的值。

flags = setsockopt(sock, sol_socket, so_linger, &stlinger, sizeof(struct

linger));

if (flags == -1

)

return sock;

setsockopt 設定 so_linger 選項:作用就是在close關閉時,保證傳送資料傳送到對方後,再徹底關閉連線。

當套介面關閉時核心將拖延一段時間(由l_linger決定)。如果套介面緩衝區中仍殘留資料,程序將處於睡眠狀態,直到

(a)所有資料傳送完且被對方確認,之後進行正常的終止序列(描述字訪問計數為0)或

(b)延遲時間到。

此種情況下,應用程式檢查close的返回值是非常重要的,因為要區分兩種狀態:

如果在資料傳送完並被確認前時間到,close將返回ewouldblock錯誤且套介面傳送緩衝區中的任何資料都丟失。

如果資料傳送完並被確認後,指定的時間才到,close的成功返回僅告訴我們傳送的資料(和fin)已由對方tcp確認,它並不能告訴我們對方應用程序是否已讀了資料。如果套介面設為非阻塞的,它將不等待close完成。

此選項指定函式close對面向連線的協議如何操作(如tcp)。核心預設close操作是立即返回,如果有資料殘留在套介面緩衝區中則系統將試著將這些資料傳送給對方。

so_linger選項用來改變此預設設定。使用如下結構:

struct linger {

int l_onoff; /* 0 = off, nozero = on */

int l_linger; /* linger time */

有下列三種情況:

1、設定 l_onoff為0,則該選項關閉,l_linger的值被忽略,等於核心預設情況,close呼叫會立即返回給呼叫者,如果可能將會傳輸任何未傳送的資料;

2、設定 l_onoff為非0,l_linger為0,則套介面關閉時tcp夭折連線,tcp將丟棄保留在套介面傳送緩衝區中的任何資料並傳送乙個rst給對方,而不是通常的四分組終止序列,這避免了time_wait狀態;

3、設定 l_onoff 為非0,l_linger為非0,當套介面關閉時核心將拖延一段時間(由l_linger決定)。如果套介面緩衝區中仍殘留資料,程序將處於睡眠狀態,直 到(a)所有資料傳送完且被對方確認,之後進行正常的終止序列(描述字訪問計數為0)或(b)延遲時間到。此種情況下,應用程式檢查close的返回值是非常重要的,如果在資料傳送完並被確認前時間到,close將返回ewouldblock錯誤且套介面傳送緩衝區中的任何資料都丟失。close的成功返回僅告訴我們傳送的資料(和fin)已由對方tcp確認,它並不能告訴我們對方應用程序是否已讀了資料。如果套介面設為非阻塞的,它將不等待close完成。

更具體的描述如下:

1、若設定了so_linger(亦即linger結構中的l_onoff域設為非零),並設定了零超時間隔,則closesocket()不被阻塞立即執行,不論是否有排隊資料未傳送或未被確認。這種關閉方式稱為「強制」或「失效」關閉,因為套介面的虛電路立即被復位,且丟失了未傳送的資料。在遠端的recv()呼叫將以wsaeconnreset出錯。

2、若設定了so_linger並確定了非零的超時間隔,則closesocket()呼叫阻塞程序,直到所剩資料傳送完畢或超時。這種關閉稱為「優雅」或「從容」關閉。請注意如果套介面置為非阻塞且so_linger設為非零超時,則closesocket()呼叫將以wsaewouldblock錯誤返回。

3、若在乙個流類套介面上設定了so_dontlinger(也就是說將linger結構的l_onoff域設為零),則closesocket()呼叫立即返回。但是,如果可能,排隊的資料將在套介面關閉前傳送。請注意,在這種情況下windows套介面實現將在一段不確定的時間內保留套介面以及其他資源,這對於想用所以套介面的應用程式來說有一定影響。

so_dontlinger 若為真,則so_linger選項被禁止。

so_linger延遲關閉連線 struct linger上面這兩個選項影響close行為;

選項          間隔    關閉方式  等待關閉與否

so_dontlinger   不關心     優雅         否

so_linger        零        強制         否

so_linger       非零       優雅         是

Socket程式設計 非阻塞connect

閱讀skynet原始碼的過程中,發現一種非阻塞connect方式。以前不知道,這次好好學習一下。文章參考自 非阻塞connect編寫方法介紹 董的部落格 tcp連線的建立涉及到乙個三次握手的過程,鑑於rtt波動範圍很大,從區域網的幾個毫秒到幾百個毫秒甚至廣域網上的幾秒。這段時間內,我們可以執行其他處...

網路程式設計 非阻塞connect詳解

一 為什麼使用非阻塞connect tcp連線的建立涉及乙個在三路握手過程,阻塞的connect一直等到客戶收到自己的syn的ack才返回,這需要至少乙個rtt時間,rtt時間波動很大從幾毫秒到幾秒。而且在沒有響應時,會等待數秒再次傳送,詳見tcpv2第828頁 總共75秒到幾分鐘的connect超...

非阻塞connect的實現

需要非阻塞connec的幾種情況 1.三路握手需要時間,這個要視具體的網路情況而定。當然也有可能失敗。在三路握手的時候我們並不需要在原地等待三路握手的完成,可以用這些時間來完成其它事情,然後當這些事情完成後,再去檢測連線是否建立 也就是三路握手是否完成 2.可以用這種技術來同時建立多個連線。web瀏...