在Linux C網路程式設計中,一共有兩種方法來關閉一個已經連接好的網路通信,它們就是close函數和shutdown函數,它們的函數原型分別為:
1 #include
2。 shutdown(intsockfd,inthowto)
7 //回傳:0——成功, 1——失敗
對一個tcp socket呼叫close()的預設動作是將該socket標記為已關閉並立即返回到呼叫該api程序中。此時,從應用層來看,該socket fd不能再被進程使用,即不能再作為read或write的參數。而從傳輸層來看,TCP會嘗試將目前send buffer中積壓的資料發到鏈路上,然後才會發起TCP的4次揮手以徹底關閉TCP連線。
調用close()是關閉TCP連線的正常方式,但這種方式有兩個限制,而這正是引入shutdown()的原因:1)close()其實只是將socket fd的引用減1,只有當此socket fd的引用計數減至0時,TCP傳輸層才會發起4次握手而真正關閉連線。而shutdown則可以直接啟動關閉連線所需的4次握手,而不用受到引用計數的限制;
2)close()會終止TCP的雙工連結。由於TCP連接的全雙工特性,可能會存在這樣的應用場景:local peer不會再向remote peer發送數據,而remote peer可能還有數據需要發送過來,在這種情況下,如果local peer想要通知remote peer自己不會再發送資料但還會繼續收資料這個事實,用close()是不行的,而shutdown()可以完成這個任務。
close函數和shutdown函數的第一個參數都是代表的是一個檔案描述子。我們知道,在Linux作業系統中,一切東西都是當作檔案來對待,所有的東西,諸如設備、記憶體都模擬成檔案;當然,網路之間的通訊也不例外。每一個通訊對話都有一個檔案描述子對應著,你對它們之間的操作就像在操作本地的檔案一樣。在shutdown函數當中,還有一個參數howto,它有一下三種值
SHUT_WR:相應地關閉寫這一半,此時用戶不能再向套接字中寫數據,內核會把緩存中的數據發送出去,接著不會再發送數據,對等端將會知道這一點。當對等端試圖去讀的時候,可能會發生錯誤。
SHUT_RDWR:關閉讀與寫兩半,此時使用者無法從套接字中讀取或寫入。它相當於再次呼叫shutdown函數,並且一次指定SHUT_RD,一次指定SHUT_WR。
SHUT_**在函數庫裡面都是由巨集定義的;由於shutdown提供了第二個,它可以精確的控制一個套接字描述符的關閉,這對close函數來說是無法實現的。在多執行緒環境中,一個描述符可能是被好幾個執行緒複製了,它們與一個檔案關聯,並且核心維護一個檔案引用計數,只有在引用計數為零的情況下close才可以關閉掉這個檔案描述符。
使用close函數有兩個限制,卻可以使用shutdown來避免:close函數把描述符的引用計數減一,僅在該計數變為0的時候,才真正的關閉套接字,而使用shutdown函數可以不管引用計數就激發了TCP的正常連線終止序列;close函數終止讀取和寫入兩個方向的資料傳輸。既然TCP連線是全雙工的,有時候我們需要告知對端我們已經完成了數據發送,我們僅僅需要關閉數據發送的一個通道,但是我們還是可以接收到對端發送過來的數據,這種控制只有利用shutdown函數才能實現。
1>.如果有多個進程共享一個套接字,close每被調用一次,計數減1,直到計數為0時,也就是所用進程都調用了close,套接字將被釋放。
2>. 在多進程中如果一個進程中shutdown(sfd,SHUT_RDWR)後其它的進程將無法進行通信. 如果一個進程close(sfd)將不會影響到其它進程.