非阻塞式socket

2021-08-18 18:36:02 字數 2460 閱讀 4478

返回錯誤ewouldblock或eagain。

套接字的預設狀態是阻塞的。這就意味著當發出乙個不能立即完成的套接字呼叫時,其進

程將被投入睡眠,等待相應操作完成。可能阻塞的套接字呼叫可分為以下四類:

( 1 ) 輸入操作,包括read 、 readv、 recv、 recvfrom和 recvmsg共5個函式。如果某個程序對乙個阻塞的tcp套接字(預設設定)呼叫這些輸入函式之,而且該套接字的接收緩衝區中沒有資料可讀,該程序將被投入睡眠,直到有一些資料到達。既然tcp是位元組流協議,該程序的喚醒就是只要有一些資料到達,這些資料既可能是單個位元組,也可以是乙個完整的tcp分節中的資料。如果想等到某個固定數目的資料可讀為止,那麼可以呼叫我們的readn函式或者指定msg_waitall標誌。

對於非阻塞的套接字,如果輸入操作不能被滿足(對於tcp套接字即至少有乙個位元組的資料可讀,對於udp套接字即有乙個完整的資料報可讀),相應呼叫將立即返回乙個ewouldblock錯誤。重新再呼叫一次,系統通過這種錯誤碼,提示程式設計師

(2) 輸出操作,包括write、writev、send、sendto和sendmsg共5個函式。對於乙個tcp套接字,核心將從應用程序的緩衝區到該套接字的傳送緩衝區複製資料(資料從使用者空間複製到核心傳送緩衝區即返回成功,至於啥時候傳送出去,這是核心的事情,不由我們控制)。對於阻塞的套接字,如果核心傳送緩衝區中沒有空間,程序將被投入睡眠,直到有空間為止。對於乙個非阻塞的tcp套接字,如果其傳送緩衝區中根本沒有空間,輸出函式呼叫將立即返回ewouldblock錯誤。如果其傳送緩衝區中僅僅有一些空間,返回值將是核心能夠複製到該緩衝區中的位元組數,也叫做不足計數。

(3)接受外來連線,即accept函式。如果對乙個阻寨的套接字呼叫accept函式,並且尚無新的連線到達,呼叫程序將被投入睡眠。如果對乙個非阻塞的套接字呼叫accept函式,並且尚無新的連線到達,accept呼叫將立即返回乙個ewouldblock錯誤。

(4) 發起外出連線,及用於tcp的connect函式,tcp連線的建立涉及乙個三路握手過程,而且connect函式一直要等到客戶收到對於自己的syn的ack為止才返回。這意味者tcp的每一次connect總會阻塞其呼叫程序至少乙個到伺服器的rtt時間。對於乙個非阻塞套接字呼叫connect,並且連線不能立即建立,連線的建立能照樣發起,不過會立刻返回乙個einprogress(在處理中的錯誤)錯誤。注意有些連線可以立即建立,通常發生在伺服器和客戶機處於同乙個主機的情況下。因此即使對於乙個非阻塞的connect ,我們也得預備connect成功返回的情況發生。

對於以上系統呼叫,nginx裡面都是通過非阻塞處理的,所以處理非阻塞是非常重要的地方。

當在乙個非阻塞的tcp套接字上呼叫connect時。connect將立即返回乙個einprogress錯誤(建立啟動但是尚未完成),不過己經發起的tcp三路握手繼續進行,我們接著使用 select設定對應的超時時間去檢測這個連線成功或者失敗即可。非阻塞的connect有三個用途:

(1) 我們可以把三路握手疊加在其他處理上。完成乙個connect要花乙個rtt時間。而rtt波動範圍很大,從區域網上的幾個毫秒到幾百個毫秒甚至是廣域網上的幾秒。這段時間內也許有我們想要執行的其他處理工作可執行。

(2) 我們可以使用這個技術同時建立多個連線。web瀏覽器都使用這種模式,包括nginx也是這樣。後期重點關注這裡。

(3) 既然使用select等待連線的建立,我們可以給select指定乙個時間限制,使得我們能夠縮短connect的超時。

重點關注的細節:

#include    "unp.h"

int connect_nonb(int sockfd, const sa *saptr, socklen_t salen, int nsec)

//阻塞與select呼叫,如果返回0,則超時發生,返回給使用者錯誤。

if (fd_isset(sockfd, &rset) || fd_isset(sockfd, &wset)) else

err_quit("select error: sockfd not set");

done:

fcntl(sockfd, f_setfl, flags); /* restore file status flags */

if (error)

return

(0);

}

對於乙個正常的阻塞式套接字,如果其上的connect呼叫在tcp三路握手完成前被中斷(譬如說捕獲了某個訊號),將會發生什麼呢?假設被中斷的connect呼叫不由核心自動重啟,那麼它將返回eintr。我們不能再次呼叫connect等待未完成的連線繼續完成。這樣做將導致返回eaddrinuse錯誤。這種情形下我們只能呼叫 select。就像本節對於非阻塞connect所做的那樣。連線建立成功時select返回套接字可寫條件,連線建立失敗時select返回套接字既可讀又可寫條件。

非阻塞式socket程式設計select

華清遠見嵌入式學院 上海中心講師。select在socket程式設計中還是比較重要的,可是對於初學socket的人來說都不太愛用select寫程式,他們只是習慣寫諸如 connect accept recv或recvfrom這樣的阻塞程式 所謂阻塞方式block,顧名思義,就是程序或是執行緒執行到這...

非阻塞式socket程式設計(select )

select在socket程式設計中還是比較重要的,可是對於初學socket的人來說都不太愛用select寫程式,他們只是習慣寫諸如connect accept recv或recvfrom這樣的阻塞程式 所謂阻塞方式block,顧名思義,就是程序或是執行緒執行到這些函式時必須等待某個事件的發生,如果...

非阻塞式socket程式設計select

select在socket程式設計中還是比較重要的,可是對於初學socket的人來說都不太愛用select寫程式,他們只是習慣寫諸如connect accept recv或recvfrom這樣的阻塞程式 所謂阻塞方式block,顧名思義,就是程序或是執行緒執行到這些函式時必須等待某個事件的發生,如果...