shutdown()

shutdown()

shutdown()是指禁止在一個套介面上進行數據的接收與發送。

簡述


禁止在一個套介面上進行數據的接收與發送。
s:用於標識一個套介面的描述字。
how:標誌,用於描述禁止哪些操作。
Linux:
#includesocket.h>
int shutdown(int sockfd,int how);
linux下成功則返回0,錯誤返回-1,錯誤碼errno:EBADF表示sockfd不是一個有效描述符;ENOTCONN表示sockfd未連接;ENOTSOCK表示sockfd是一個描述符而不是socket描述符。
how的方式有三種分別是
SHUT_RD(0):關閉sockfd上的讀功能,此選項將不允許sockfd進行讀操作。
SHUT_WR(1):關閉sockfd的寫功能,此選項將不允許sockfd進行寫操作。
SHUT_RDWR(2):關閉sockfd的讀寫功能。
Windows:
#include 或#include
int PASCAL FAR shutdown( SOCKET s, int how);
how的方式有三種分別是
SD_RECEIVE(0):Shutdown receive operations.
SD_SEND(1):Shutdown send operations.
SD_BOTH(2):Shutdown both send and receive operations.

註釋


shutdown()函數用於任何類型的套介面禁止接收、禁止發送或禁止收發。
如果how參數為0,則該套介面上的後續接收操作將被禁止。這對於低層協議無影響。對於TCP協議,TCP窗口不改變並接收前來的數據(但不確認)直至窗口滿。對於UDP協議,接收並排隊前來的數據。任何情況下都不會產生ICMP錯誤包。
若how為1,則禁止後續發送操作。對於TCP,將發送FIN。
若how為2,則同時禁止收和發。
請注意shutdown()函數並不關閉套介面,且套介面所佔有的資源將被一直保持到closesocket()調用。

評註


無論SO_LINGER設置與否,shutdown()函數不會阻塞。
一個應用程序不應依賴於重用一個已被shutdown()禁止的套介面。特別地,一個WINDOWS套介面實現不必支持在這樣的套介面上使用connect()調用。
返回值:
如果沒有錯誤發生,shutdown()返回0。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
錯誤代碼:
WSANOTINITIALISED:在使用此API之前應首先成功地調用WSAStartup()。
WSAENETDOWN:WINDOWS套介面實現檢測到網路子系統失效。
WSAEINVAL:how參數非法。
WSAEINPROGRESS:一個阻塞的WINDOWS套介面調用正在運行中。
WSAENOTCONN:套介面未連接(僅適用於SOCK_STREAM類型套介面)。
WSAENOTSOCK:描述字不是一個套介面。
擴展知識:
Socket的close與shutdown
close-----關閉本進程的socket id,但鏈接還是開著的,用這個socket id的其它進程還能用這個鏈接,能讀或寫這個socket id。
shutdown--則破壞了socket 鏈接,讀的時候可能偵探到EOF結束符,寫的時候可能會收到一個SIGPIPE信號,這個信號可能直到socket buffer被填充了才收到。
更多關於close和shutdown的說明:
1. 如果有多個進程共享一個套接字,close每被調用一次,計數減1,直到計數為0時,也就是所用進程都調用了close,套接字將被釋放。
2. 在多進程中如果一個進程中shutdown(sfd, SHUT_RDWR)后其它的進程將無法進行通信. 如果一個進程close(sfd)將不會影響到其它進程. 得自己理解引用計數的用法了. 有Kernel編程知識的更好理解了.
3. 只要TCP棧的讀緩衝里還有未讀取(read)數據,則調用close時會直接向對端發送RST
4. shutdown與socket描述符沒有關係,即使調用shutdown(fd, SHUT_RDWR)也不會關閉fd,最終還需close(fd)。
5. 可以認為shutdown(fd, SHUT_RD)是空操作,因為shutdown后還可以繼續從該socket讀取數據,這點也許還需要進一步證實。
6. 在已發送FIN包后write該socket描述符會引發EPIPE/SIGPIPE。
7. 當有多個socket描述符指向同一socket對象時,調用close時首先會遞減該對象的引用計數,計數為0時才會發送FIN包結束TCP連接。shutdown不同,只要以SHUT_WR/SHUT_RDWR方式調用即發送FIN包。
8. SO_LINGER與close,當SO_LINGER選項開啟但超時值為0時,調用close直接發送RST(這樣可以避免進入TIME_WAIT狀態,但破壞了TCP協議的正常工作方式),SO_LINGER對shutdown無影響。
9. TCP連接上出現RST與隨後可能的TIME_WAIT狀態沒有直接關係,主動發FIN包方必然會進入TIME_WAIT狀態,除非不發送FIN而直接以發送RST結束連接。
參見:
connect(), socket(),bind()