2011-11-24 175 views
10

您好我正在閱讀TLPI(Linux編程接口),我有一個關於connect()的問題。是否爲TCP套接字連接()塊?

據我所知,如果listen()的未決連接數沒有達到「backlog」,connect()會立即返回。 否則會阻塞。 (根據圖56-2)

但是對於TCP套接字,它將一直阻塞,直到調用服務器端的accept()爲止(根據圖61-5)。

我正確嗎? 因爲我在示例代碼(p.1265)中看到,它調用listen()來監聽特定端口,然後在調用accept()之前調用connect()到該端口。

因此connect()在這種情況下永遠阻塞,不是嗎?

謝謝!

+0

如果這就是圖56-2所顯示的,那就錯了。 – EJP

回答

19

關於網絡幾乎沒有任何「立即」的東西可以在途中丟失,而理論上應立即執行的操作在實踐中可能不會這樣做,並且在任何情況下都存在端到端傳輸時間。

然而

  • 上的TCP套接字連接

    ()是一個阻塞操作,除非套接字描述符放入非阻塞模式。

  • 操作系統負責TCP握手,當握手完成時,connect()返回。 (即, connect()不會阻塞,直到另一端調用accept())

  • 成功的TCP握手將排隊等待服務器應用程序,並且可以在隨後的accept()''編輯。

+0

只是想補充一下'connect'只是等待握手而不是服務器調用'accept',這是因爲兩個原因:第一個是來自客戶端的他在握手後連接;第二個是因爲可以在握手之間傳遞任意時間,並且在服務器調用「accept」之前,這確實是永遠的。 –

+1

即使沒有答案的其餘部分,「幾乎沒有任何'立即'」單獨保證+1。即使在非阻塞模式下,這對於很多操作也是如此。有時甚至可能會很快,甚至對於那些你不會期望的事情。 – Damon

+0

@JoachimPileborg @nos如果'connect()'在服務器調用accept()之前返回,如果客戶端在服務器調用accept()之前嘗試'send(),會發生什麼? – Flash

3

connect默認情況下是阻止呼叫,但您可以通過傳遞socketSOCK_NONBLOCK標誌使其不阻塞。

+4

或者更常見的是,使用fcntl的「傳統」BSD套接字函數和O_NONBLOCK。 SOCK_NONBLOCK是Linux專用的。 – MarkR

2

connect()阻塞,直到完成TCP 3次握手。在監聽端的握手由內核中的TCP/IP協議棧處理,並在沒有通知用戶進程的情況下完成。只有在握手完成後(並且發起者可以從connect()調用已經返回),accept()在用戶進程中可以拾取新的套接字並返回。沒有等待接受()需要完成握手。

原因很簡單:如果您有單線程進程監聽連接,並且需要等待accept()來建立連接,則在處理另一個請求時無法對TCP SYN進行響應。初始端的TCP堆棧將重新發送,但是在適度加載的服務器上機率很高,這個重新發送的數據包仍然會到達,而沒有accept()掛起並且會再次丟棄,導致醜陋的延遲和連接超時。