2017-01-25 28 views
3

在此MSDN頁:爲什麼要在關閉套接字之前使用shutdown()?

Sending and Receiving Data on the Client

它建議關閉套接字的發送方使用:

shutdown(SOCK_ID, SD_SEND); 

爲什麼要這樣呢?

也許我不就得了,它只是一個建議?也許是爲了節省內存?也許速度?

有沒有人有想法?

+0

它*可能會釋放一些用於發送的資源?至少套接字描述符本身將被釋放。但我並沒有真正看到它的理由,而不是你鏈接到的程序。 –

+0

您的問題包含一個常見但嚴重的混淆。你說「它建議關閉socket的發送端」。不,不是的。套接字沒有邊。它建議關閉socket指向的* connection *的發送端。一旦你意識到這種差異有多重要,你會發現你別無選擇。 'closesocket'函數是套接字上的操作,而不是連接。如果你想正常關閉連接,你有什麼選擇? –

+2

@Someprogrammerdude套接字描述符本身肯定不會被釋放。否則,以下關閉(a)不可能工作,(b)將是毫無意義的,但事實並非如此。 – EJP

回答

2

答案是shutdown()文檔中:

如果該參數是如何SD_SEND,隨後到send函數調用是不允許的。 對於TCP套接字,所有數據被髮送和確認由接收FIN將被髮送。

...

,以確保所有數據的發送和在關閉之前在一個連接的插座接受,應用程序應該使用shutdown調用closesocket之前關閉連接。一種方法來等待遠端已經發送的所有數據,併發起了一個優美的斷開通知使用WSAEventSelect功能如下:

  1. 呼叫WSAEventSelectFD_CLOSE註冊通知。
  2. 呼叫shutdownhow=SD_SEND
  3. 當接收FD_CLOSE,調用recvWSARecv直到函數成功完成,並且指示收到零個字節。如果SOCKET_ERROR已返回,則無法正常斷開連接。
  4. 呼叫closesocket

另一種方法來等待遠端已經發送的所有數據,併發起了一個優美的脫節用途通知重疊接聽電話如下:

  1. 呼叫shutdownhow=SD_SEND
  2. 呼叫recvWSARecv直到函數成功完成,並表示收到零個字節。如果SOCKET_ERROR已返回,則無法正常斷開連接。
  3. 呼叫closesocket

...

欲瞭解更多信息,請參閱Graceful Shutdown, Linger Options, and Socket Closure部分。

換句話說,至少對於TCP,調用shutdown(SD_SEND)通知你完成發送更多的數據同行,那你可能會很快結束你的連接端。最好,同行也會爲你做同樣的禮貌。這樣,兩個同伴都可以知道兩端故意關閉連接。這被稱爲曼妙斷開連接,而不是一個流產異常斷開連接。

默認情況下,如果你不叫shutdown(SD_SEND)closesocket()將嘗試爲您執行正常關機除非插座的linger選項被禁用。最好不要依賴這種行爲,除非你有充分的理由,否則在致電closesocket()之前,你應該總是自己打電話shutdown()

+0

實際上,'closesocket'只會在你關閉連接的最後一個引用時執行。如果你試圖關閉連接,只調用'shutdown'就可以保證你做到了,並且知道它是否工作。 'closesocket'函數可能會成功,對連接什麼都不做。 –

+0

@DavidSchwartz:我假設你指的是通過使用['WSADuplicateSocket()'](https://msdn.microsoft.com/en-us/library/windows/desktop/ms741565.aspx) ?否則,我不知道你的意思。 –

+0

除非逗留是*啓用*零超時,*或*您的套接字接收緩衝區中有未讀數據。這種同步關閉的情況相當專業化,本身並不是一個足以推薦'shutdown()'的普遍理由。我從來沒有用過它。 – EJP

0

有與發送或插座上接收操作相關聯的特定資源,插座要麼使用或關閉。有關閉的原因與資源管理無關。關閉套接字是實現所謂的優雅關閉協議,它允許通信雙方實現連接正在關閉並允許最小化數據丟失。

2

這是不必要的和多餘的,除了下列情況:

  1. 你想實現由雷米勒博引用文檔中描述的同步關閉。
  2. 插座已經以某種方式被複制,例如,它是與子進程或父進程共享的,或者通過API共享的,並且您希望現在可以確保FIN發送到
  3. 您的應用程序協議要求對等方收到關機,但需要繼續發送。例如,在編寫代理服務器時可能會出現這種情況。
  4. 您的套接字接收緩衝區中可能有未讀數據,並且您希望關閉並忽略它,並在引發連接重置之前發送FIN,當您關閉時會發生連接重置,如果存在未讀未決數據。

這是我所見過的大約30年跨越的唯一案例:有可能是別人,但我不知道他們。

+0

難道你幾乎總是想實現同步關閉?我不知道我遇到過不想同步關閉的情況。如果在拆解過程中發生錯誤,您想記錄錯誤的情況如何?你的回答讓95%的情況聽起來像是個例外! –

+0

@DavidSchwartz不,我並不總是想實現同步關閉。我懷疑在25年的網絡編程中,我曾經編碼過一個,甚至看過一個。 HTTP是地球上最常用的應用協議,它不使用它。 TLS也沒有。我還沒有研究過任何其他應用協議。 – EJP

+0

如果您無法在Windows上執行操作,如何幹淨地關閉HTTP連接並記錄錯誤?你可以調用'closesocket'並且沒有錯誤,並且不能保證連接完全關閉。 –

相關問題