歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Unix知識 >> Unix基礎知識

UNIX網絡編程:shutdown與close函數的區別

假設server和client 已經建立了連接,server調用了close, 發送FIN 段給client(其實不一定會發送FIN段,後面再說),此時server不能再通過socket發送和接收數據,此時client調用read,如果接收到FIN 段會返回0,但client此時還是可以write 給server的,write調用只負責把數據交給TCP發送緩沖區就可以成功返回了,所以不會出錯,而server收到數據後應答一個RST段,表示服務器已經不能接收數據,連接重置,client收到RST段後無法立刻通知應用層,只把這個狀態保存在TCP協議層。如果client再次調用write發數據給server,由於TCP協議層已經處於RST狀態了,因此不會將數據發出,而是發一個SIGPIPE信號給應用層,SIGPIPE信號的缺省處理動作是終止程序。

有時候代碼中需要連續多次調用write,可能還來不及調用read得知對方已關閉了連接就被SIGPIPE信號終止掉了,這就需要在初始化時調用sigaction處理SIGPIPE信號,對於這個信號的處理我們通常忽略即可,signal(SIGPIPE, SIG_IGN); 如果SIGPIPE信號沒有導致進程異常退出,write返回-1並且errno為EPIPE。

#include <unistd.h>  
 int close(int fd);

close 關閉了自身數據傳輸的兩個方向。

close一個TCP套接字的默認行為是把該套接字標記成已關閉,然後立即返回到調用進程。該套接字描述符不能再由調用進程使用,也就是說它不能作為read或write的第一個參數。然而TCP將嘗試發送已排隊等待發送到對端的任何數據,發送完畢後發生的是正常的TCP連接終止序列。

我們可以通過SO_LINGER套接字選項可以用來改變TCO套接字的這種默認行為。

終止網絡連接的通常方法是調用close函數。不過close有兩個限制,卻可以使用shutdown來避免。

(1)close把描述符的引用計數減1,僅在該計數變為0時才關閉套接字。使用shutdown可以不管引用計數就激發TCP的正常連接終止序列。

(2)close終止讀和寫兩個方向的數據傳送。既然TCP連接是全雙工的,有時候我們需要告知對端我們已經完成了數據發送,即使對端仍然有數據要發送給我們。

#include <sys/socket.h>  
int shutdown(int sockfd,int howto);  
      返回:若成功則為0,若出錯則為-1

該函數的行為依賴於howto參數的值:

SHUT_RD    關閉連接的讀這一半,套接字中不在有數據可接收,而且套接字接收緩沖區中的現有數據都被丟失。進程不能再對這樣的套接字調用任何讀函數。對一個TCP套接字這樣調用shutdown函數後,由該套接字接收的來自對端的任何數據都被確認,然後悄然丟棄。

SHUT_WR    關閉連接的寫這一半,對於TCP套接字,這稱為半關閉。當前留在套接字發送緩沖區中的數據將被發送掉,後跟TCP的正常連接終止序列。我們已經說過了,不管套接字描述符的引用計數是否等於0,這樣的寫半部關閉照樣執行。進程不能再對這樣的套接字調用任何寫函數。

SHUT_RDWR  連接的讀半部和寫半部都關閉,這與調用shutdown兩次等效:第一次調用指定SHUT_RD,第二次調用指定SHUT _WR。

作者:csdn博客 ctthuangcheng

查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/

Copyright © Linux教程網 All Rights Reserved