TCP之非阻塞connect和accept


套接字的默認狀態是阻塞的,這就意味着當發出一個不能立即完成的套接字調用時,其進程將被投入睡眠,等待響應操作完成,可能阻塞的套接字調用可分為以下四類:

(1) 輸入操作,包括read,readv,recv,recvfrom,recvmsg;

(2) 輸出操作,包括write,writev,send,sendto,sendmsg;

(3) 接受外來連接,即accept函數。

(4) 發起外出連接,即tcp的connect函數;

 

非阻塞connect:

當一個非阻塞的tcp套接字上調用connect時,connect將立即返回一個EINPROGRESS錯誤,不過已經發起的tcp三路握手繼續進行。我們接着使用select檢測這個連接或成功或失敗的已建立條件。非阻塞connect有三個用途:

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

(2) 我們可以使用這個技術同時建立多個連接;這個技術隨着web瀏覽器流行起來;

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

非阻塞connect細節:

(1) 盡管套接字是非阻塞的,如果連接到的服務器在同一個主機上,那么當我們調用connect時候,連接通常立刻建立,我們必須處理這種情形;

(2) 源自Berkeley的實現(和posix)有關select和非阻塞connect的以下兩個原則:

--(a) 當連接成功建立時,描述符變為可寫;

--(b) 當連接建立遇到錯誤時,描述符變為既可讀又可寫;

 

非阻塞accept:

在比較忙的服務器中,在建立三次握手之后,調用accept之前,可能出現客戶端斷開連接的情況,再這樣的情況下;如,三次握手之后,客戶端發送rst,然后服務器調用accept。posix指出這種情況errno設置為CONNABORTED;

注意Berkeley實現中,沒有返回這個錯誤,而是EPROTO,同時完成三次握手的連接會從已完成隊列中移除;在這種情況下,如果我們用select監聽到有新的連接完成,但之后又被從完成隊列中刪除,此時如果調用阻塞accept就會產生阻塞;

解決辦法:

(1) 使用select監聽套接字是否有完成連接的時候,總是把這個監聽套接字設置為非阻塞;

(2) 在后續的accept調用中忽略以下錯誤,EWOULDBLOCK(Berkeley實現,客戶中止連接), ECONNABORTED(posix實現,客戶中止連接), EPROTO(serv4實現,客戶中止連接)和EINTR(如果有信號被捕獲);

 


免責聲明!

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



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