網路程式設計中time_wait的作用和套接字選項SO_REUSEADDR
這兩天看APUE為一個簡單的問題特別惱火,該問題起源於兩個套接字選項就是SO_REUSEADDR和SO_REUSEPORT其實在看的過程中問學長了,學長解釋的也比較清楚,就是自己悟性不好,一時半會沒理解。自己在網上找了幾篇優秀的部落格看了,受益頗多!
先從套接字選項SO_REUSEADDR說起,當一個沒有設定該選項的伺服器與客戶端建立連線後。然後中斷伺服器,此時要是馬上建立連線的話肯定會出現套接字繫結錯誤的現象。像圖中我親自執行的樣子!真的坑了!
這個epoll伺服器和客戶端是我之前寫的可以可在這裡找到,也可以自己測試執行,看下真相。我執行時故意把那個套接字選項去了,然後連線了一個客戶端就將伺服器程式ctrl+c了。伺服器埠是8000沒錯,可以看出斷開連線後,服務端套接字還處於time_wait2,相信看了TCP斷開連線四次揮手的人都知道這是服務端在等客戶端傳送確認斷開連線的資料所維持的狀態!因此原伺服器IP和埠還處於繫結狀態,對於TCP肯定不允許相同的IP和埠的多個伺服器進行捆綁!所以導致錯誤的出現,但是等待過上大概兩分鐘後就可以繫結成功了。
一般來說,不要主動將伺服器掛掉,因為這是比較浪費資源的,當很多客戶端和伺服器進行連線後,主動掛掉,就會讓很多繫結好的ip和埠進入到time_wait狀態,一段時間無法再次連線
嗯,設定上這個地址複用的SO_REUSEADDR選項
再次執行伺服器,連線客戶端後,再掛掉伺服器,然後再重啟伺服器後,在系統中檢視Tcp連線情況,就會如下所示。系統允許繫結相同的埠了。為什麼?觀察發現,ip 由localhost 變為0.0.0.0了,在伺服器中,0.0.0.0指的是本機上的所有IPV4地址,如果一個主機有兩個IP地址,192.168.1.1 和 10.1.2.1,並且該主機上的一個服務監聽的地址是0.0.0.0,那麼通過兩個ip地址都能夠訪問該服務。
前面解釋的差不多了,那麼對於套接字選項作用在unp中是這樣解釋的:
1.SO_REUSEADDR允許啟動一個監聽伺服器並捆綁其眾所周知的埠,即使以前建立的將該埠用作他們的本地埠的連線仍存在。 這種條件下通常是這樣碰到的: a)啟動一個監聽伺服器 b)連線請求到達 c)監聽伺服器終止 d)重啟監聽伺服器 2.允許在同一埠上啟動同一伺服器的多個例項,只要每個例項捆綁一個不同的本地IP地址即可。 3.SO_REUSEADDR 允許單個程序捆綁同一埠到多個套接字上,只要每次捆綁指定不同的本地IP地址即可。 4.SO_REUSEADDR允許完全重複的捆綁:當一個IP地址和埠號已繫結到某個套接字上時,如果傳輸協議支援,同樣的IP地址和埠還可以捆綁到另一個套接字上。一般來說本特性僅支援UDP套接字。
這裡就利用的是他的第二點特性!
那麼我們進一步探究一下他為什麼會在伺服器關閉後還有fin_wait和time_wait呢?
fin_wait狀態是斷開連線過程中,伺服器向客戶端傳送fin 包,進入fin_wait1狀態,然後客戶端關閉連線後並回復ack進入closed_wait狀態,伺服器端收到ack後維持fin_wait2狀態!
而time_wait 狀態就是客戶端在給服務端傳送fin 的狀態,只要客戶端沒收到伺服器端的再次確認的資料ack包,原埠和IP就維持繫結,大概就兩分鐘的時間,這一步的作用保證了當前建立的連線不會對之後建立的新連線造成不可預知的影響,當時間過去後,連線中的一些資料會自動消失在網路中。這也證明了TCP確實是比較可靠的傳輸層協議!而我們設定的SO_REUSEADDR自己對於其理解就是,伺服器在斷開連線後,允許在time_wait存在的情況下,給伺服器分配一個其他的本機IP,而不是使用原有IP
,再繫結相同的埠,實現TCP的成功連線。
emmmm,這部分知識總結就到這裡,我的表達能力確實不是很好,不,是很不好!要是還有疑問的話,我推薦上幾篇相關部落格!他們講的確實很不錯,很清楚。