一 Shutdown函數
有時候,我們想給服務器發送一個FIN,告訴它們我們已經完成了數據發送,但是仍然保持套接字描述符打開以便讀取。
這時候就需要一種關閉TCP連接其中一半的方法。
確切地說,close() / closesocket() 用來關閉套接字,將套接字描述符(或句柄)從內存清除,之後再也不能使用該套接字,與C語言中的 fclose() 類似。應用程序關閉套接字後,與該套接字相關的連接和緩存也失去了意義,TCP協議會自動觸發關閉連接的操作。
shutdown() 用來關閉連接,而不是套接字,不管調用多少次 shutdown(),套接字依然存在,直到調用 close() / closesocket() 將套接字從內存清除。
調用 close()/closesocket() 關閉套接字時,或調用 shutdown() 關閉輸出流時,都會在發送緩衝區中的數據發送完畢後向對方發送 FIN 包。FIN 包表示數據傳輸完畢,計算機收到 FIN 包就知道不會再有數據傳送過來了。
Close函數的默認情況:
在套接字上不再發出發送或接收請求;套接字發送緩衝區中的內容被髮送到對端。
如果描述符引用計數變爲0,在發送完發送緩衝區中的數據後,跟以正常的TCP連接終止序列(發送FIN)。套接字接收緩衝區中的數據被丟棄。
Shutdown函數(SHUT_WR)
在套接字上不再發出發送請求;進程仍可從套接字接收數據;套接字發送緩衝區中的數據被髮送到對端,後跟以正常的TCP連接終止序列(發送FIN),對套接字接收緩衝區無任何影響。
shutdown(shut_wr)實現優雅關閉的點在(自己總結的):
(1)close會關閉套接字2個方向的連接,即使對方還有數據需要發送或即使接收緩衝區中有數據未被處理。
而shutdown只關閉一個方向的連接,客戶端還會收到對方發送的數據,接收緩衝區中的數據也會被處理。
(2)
close調用後通常立即返回(在發送完發送緩衝區的數據),很大可能在服務端讀套接字接收緩衝區中的剩餘數據前返回。對於服務器主機來說,服務器應用進程在讀這些剩餘數據之前就崩潰(會發送FIN)是完全可能的,而客戶端應用進程不會知道。
後跟一個read調用的shutdown一直等到接收到了對端的FIN才返回。保證對方應用進程已成功讀取接收緩衝區中的數據。且對方數據也發鬆完畢。
二 TCP套接字選項SO_LINGER
本選項指定close函數對面向連接的協議如何操作。
默認操作是close函數立即返回,如果有數據殘留在發送緩衝區,系統會試着把這些數據發送給對端。