1. 程式人生 > >【slighttpd】基於lighttpd架構的Server專案實戰(5)—TCP的TIME_WAIT狀態

【slighttpd】基於lighttpd架構的Server專案實戰(5)—TCP的TIME_WAIT狀態

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50637549

上一節我們已經開發了一個簡單的echo伺服器,在這裡我們先不急著繼續下去,先看看一些小細節!

在listener的程式碼中,對於監聽套接字,我設定了SO_REUSEADDR這個選項,那麼,這個選項有什麼用呢?

int reuse = 1;
setsocket(listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

要明白這個問題,我們先看看tcp關閉連線的四次握手:

可以看到,主動關閉的一端將經歷TIME_WAIT狀態。

TIME_WAIT狀態有兩個存在的理由——

一、可靠地實現TCP全雙工連線的終止: 
假設主動關閉端最後傳送的ACK丟失了,對端將重新發送FIN,主動關閉端只有在維護狀態資訊的情況下才能重傳最後那個ACK。否則,主動關閉端將會響應一個RST,對端會將此響應標記為錯誤,所以不能進行正常的關閉。

二、允許老的重複分節在網路中消逝: 
假設我們在兩個主機之間建立了一個TCP連線,之後關閉這個連線,過一會又在相同的IP地址和埠之間建立另一個連線。由於IP地址和埠號與之前相同,所以如果出現上一個連線的老的重複分組,將會影響到新的連線。為解決這個問題,TCP將不會給處於TIME_WAIT狀態的連線發起這個新的連線。

為解決以上問題,TIME_WAIT狀態需要持續一定的時間,所以TIME_WAIT也被稱為2MSL等待狀態,一般持續時間在1分鐘到4分鐘之間。

關於TCP的各個狀態,建立與終止等情況,可以參考下我的另一篇博文:
《TCP/IP詳解 卷1:協議》 讀書筆記 第十八章 TCP連線的建立與終止

因此,伺服器端程式啟用SO_REUSEADDR選項的好處是:如果服務端程式由於某種錯誤操作關閉了,我們需要立馬重啟服務程式,但是TIME_WAIT還佔用著這些地址埠資源讓你的服務無法開啟。當開啟SOREUSEADDR這個選項之後,就允許地址埠的重複繫結,使得服務快速重啟。

另外,既然提到TIME_WAIT,有另一個問題需要提一下——

高併發TCP伺服器中主動關閉的一方最好是客戶端: 
因為對於高併發伺服器來說檔案描述符資源是十分重要的,如果對於每一個連線都要經歷TIME_WAIT這個2MSL的時長,勢必造成資源不能馬上覆用的浪費。對於客戶端,一般很少有併發資源限制,所以客戶端執行主動關閉是比較合適的。