首頁  >  文章  >  php教程  >  linux網路程式設計--shut_down和close()函數的區別

linux網路程式設計--shut_down和close()函數的區別

高洛峰
高洛峰原創
2016-12-13 15:46:071863瀏覽

在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_RD:關閉讀這一半,此時用戶不能再從這個套接字讀數據,這個套接口接收到的數據都會被丟棄,對等方不知道這個過程。關閉連線的讀端。也就是該套接字不再接受數據,任何目前在套接字接受緩衝區的數據將被丟棄。進程將不能對該套接字發出任何讀取操作。對TCP套接字該呼叫之後接受到的任何資料將被確認然後無聲的丟棄掉。


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)將不會影響到其它進程.

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn