1. 程式人生 > 實用技巧 >TCP連線半關閉

TCP連線半關閉

如果將客戶端與伺服器之間的網路作為全雙工管道來考慮,請求是從客戶端向伺服器傳送,應答是從伺服器向客戶端傳送,其如下圖所示:

上圖假設RTT為8,且伺服器沒有處理時間且請求大小與應答大小相同。既然從管道發出到管道的另一端存在延遲,而管道是全雙工的,僅僅使用了管道的1/8,對於停-等方式對於互動式輸入是合適的。

如果以批量的方式輸入,客戶端以網路可接受的最快速度持續傳送請求,伺服器也以相同的速度處理它們併發迴應答。這就將導致在時刻7的時候,管道充滿,如下圖所示:

在上圖中,假設在時刻8的時候,發出一個請求,我們並不能立即關閉連線,因為管道中還有其他的請求和應答,這時如果程式直接從main結束,並不意味著同時完成了從套接字的讀入,可能有請求在去往伺服器的路上,或者仍然有應答在返回客戶的路上。

我們需要一種關閉TCP連線其中一半的方法。也就是說,要給伺服器傳送一個FIN,告訴伺服器已經完成了資料傳送,但仍然保持套接字開啟以便讀取,這將由shutdown函式完成。

shutdown函式

終止網路連線的通常方法是呼叫close函式。但是close函式有兩個限制,卻可以使用shutdown函式來避免:

  1. close把描述符的引用計數減一,僅在該計數變為0時才關閉套接字。但是使用shutdown中可以不管引用計數就激發TCP的正常連線終止序列。
  2. close終止讀和寫兩個方向的資料傳送。既然TCP連線是全雙工的,有時候我們需要告知對端我們已經完成了資料傳送,即使對端仍有資料要傳送給我們。

shutdown函式宣告

#include <sys/socket.h>
int shutdown(int sockfd, int howto);

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

SHUT_RD:關閉連線的讀這一半。套接字中不再有資料可接收,而且套接字接收緩衝區中的現有資料被丟棄。程序不再對這樣的套接字呼叫任何讀函式。對一個TCP套接字這樣的呼叫shutdown函式後,由該套接字接收的來自對端的任何資料都被確認,然後悄然丟棄。

SHUT_WR:關閉連線的寫這一半。對於TCP套接字,這成為半關閉。當前留在套接字傳送緩衝區中的資料將被髮送掉,後跟TCP的正常連線終止序列。不管套接字描述符的引用計數是否等於0,這樣的寫半部分照樣執行。程序不能再對這樣的套接字呼叫任何寫函式。

SHUT_RDWR:連線的讀半部分和寫半部分。這與呼叫shoudown函式兩次等效:第一次指定SHUT_RD,第二次呼叫指定SHUT_WR。

shutdown和colse的操作和SO_LINGER套接字選項的值有關。