1. 編寫TCP/SOCK 服務時,SO_REUSEADDR究竟是什麼意思?服務器
這個套接字選項通知內核,若是端口忙,但TCP狀態處於TIME_WAIT,能夠重用端口。若是端口忙,TCP狀態處於其餘狀態,重用端口時依舊指明「地址已經在使用中」。若是你的服務程序中止後向馬上重啓,而新套接字依舊使用同一個端口,此時SO_REUSEADDR選項很是有用。可是必須意識到,此時任何非指望數據到達,均可能致使服務程序反應混亂。網絡
一個套接字由五個部分組成:協議,本地地址,本地端口,遠程地址和遠程端口。SO_REUSEADDR僅僅表示能夠重用本地地址,本地端口。併發
2. 爲何須要TIME_WAIT狀態?socket
假設最後的ACK丟失,server將重發FIN,client必須維護TCP狀態信息以即可以重發最後的ACK,不然將會發送RST,結果server認爲發生錯誤。TCP實現必須可靠地終止鏈接的兩個方向,因此client必須進入TIME_WAIT狀態。ui
此外,考慮一種狀況,TCP實現可能面臨着前後兩個相同的五元組。若是前一個鏈接處於TIME_WAIT狀態,而容許另外一個擁有相同五元組鏈接出現,可能處理TCP報文時,兩個鏈接互相干擾。因此使用SO_REUSEADDR選項就須要考慮這種狀況。.net
3. 什麼是2MSLserver
MSL是Maximum Segment Lifetime,譯爲「報文最大生存時間」,他是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。
由於TCP報文(segment)是IP數據報(datagram)的數據部分,而IP頭中有一個TTL域,TTL是time to live的縮寫,中文能夠譯爲「生存時間」,這個生存時間是由源主機設置初始值但不是存的具體時間,而是存儲了一個IP數據報能夠通過的最大路由數,每通過一個處理他的路由器此值就減1,當此值爲0則數據報將被丟棄,同時發送ICMP報文通知源主機。
RFC 793中規定MSL爲2分鐘,實際應用中經常使用的是30秒,1分鐘和2分鐘等
2MSL即兩倍的MSL,TCP的TIME_WAIT狀態也稱爲2MSL等待狀態,當TCP的一端發起主動關閉,在發出最後一個ACK包後,即第3次握手完成後發送了第四次握手的ACK包後就進入了TIME_WAIT狀態,必須在此狀態上停留兩倍的MSL時間。
等待2MSL時間主要目的是怕最後一個ACK包對方沒收到,那麼對方在超時後將重發第三次握手的FIN包,主動關閉端接到重發的FIN包後能夠再發一個ACK應答包。
在TIME_WAIT狀態時兩端的端口不能使用,要等到2MSL時間結束纔可繼續使用。
當鏈接處於2MSL等待階段時任何遲到的報文段都將被丟棄。不過在實際應用中能夠經過設置SO_REUSEADDR選項達到沒必要等待2MSL時間結束再使用此端口。blog
TTL與MSL是有關係的但不是簡單的相等的關係,MSL要大於等於TTL。接口
4. 爲何TIME_WAIT狀態須要保持2MSL這麼長的時間?進程
若是TIME_WAIT狀態保持時間不足夠長,第一個鏈接就正常終止了。第二個擁有相同五元組的鏈接出現,而第一個鏈接的重複報文到達,干擾了第二個鏈接。TCP事先必須防止某個鏈接的重複報文在鏈接終止後出現,因此讓TIME_WAIT狀態保持時間足夠長(2MSL),鏈接相應方向的上的TCP報文要麼徹底響應完畢,要麼被丟棄。創建第二個鏈接的時候,不會混淆。
2MSL等待狀態
TIME_WAIT狀態也稱爲2MSL等待狀態。每一個具體TCP實現必須選擇一個報文段最大生存時間MSL(Maximum Segment Lifetime)。它是任何報文段被丟棄前在網絡內的最長時間。咱們知道這個時間是有限的,由於TCP報文段以IP數據報在網絡內傳輸,而IP數據報則有限制其生存時間的TTL字段。
對一個具體實現所給定的MSL值,處理的原則是:當TCP執行一個主動關閉,併發回最後一個ACK,該鏈接必須在TIME_WAIT狀態停留的時間爲2倍的MSL。這樣可以讓TCP再次發送最後的ACK以防這個ACK丟失(另外一端超時並重發最後的FIN)。
這種2MSL等待的另外一個結果是這個TCP鏈接在2MSL等待期間,定義這個鏈接的套接口(客戶的IP地址和端口號,服務器的IP地址和端口號)不能再被使用。這個鏈接只能在2MSL結束後才能再被使用。遺憾的是,大多數TCP實現(如伯克利版)強加了更爲嚴格的限制。在2MSL等待期間,套接口中使用的本地端口在默認狀況下不能再被使用。
在鏈接處於2MSL等待時,任何遲到的報文段將被丟棄。由於處於2MSL等待的、由該套接口對(socket pair)定義的鏈接在這段時間內不能被再用,所以當要創建一個有效的鏈接時,來自該鏈接的一個較早替身( incarnation)的遲到報文段做爲新鏈接的一部分不可能不被曲解(一個鏈接由一個插口對來定義。一個鏈接的新的實例( instance)稱爲該鏈接的替身)。
客戶執行主動關閉並進入TIME_WAIT是正常的。服務器一般執行被動關閉,不會進入TIME_WAIT狀態。這暗示若是咱們終止一個客戶程序,並當即從新啓動這個客戶程序,則這個新客戶程序將不能重用相同的本地端口。這不會帶來什麼問題,由於客戶使用本地端口,而並不關心這個端口號是什麼。
然而,對於服務器,狀況就有所不一樣,由於服務器使用熟知端口。若是咱們終止一個已經創建鏈接的服務器程序,並試圖當即從新啓動這個服務器程序,服務器程序將不能把它的這個熟知端口賦值給它的端點,由於那個端口是處於2MSL鏈接的一部分。在從新啓動服務器程序前,它須要在1~4分鐘。
儘管許多具體的實現中容許一個進程從新使用仍處於2MSL等待的端口(一般是設置選項SO _REUSEADDR),但TCP不能容許一個新的鏈接創建在相同的插口對上。
平靜時間的概念 對於來自某個鏈接的較早替身的遲到報文段, 2MSL等待可防止將它解釋成使用相同插口對的新鏈接的一部分。但這隻有在處於2MSL等待鏈接中的主機處於正常工做狀態時纔有效。若是使用處於2MSL等待端口的主機出現故障,它會在MSL秒內從新啓動,並當即使用故障前仍處於2MSL的插口對來創建一個新的鏈接嗎?若是是這樣,在故障前從這個鏈接發出而遲到的報文段會被錯誤地看成屬於重啓後新鏈接的報文段。不管如何選擇重啓後新鏈接的初始序號,都會發生這種狀況。 爲了防止這種狀況,RFC 793指出TCP在重啓動後的MSL秒內不能創建任何鏈接。這就稱爲平靜時間(quiet time)。只有極少的實現版遵照這一原則,由於大多數主機重啓動的時間都比MSL秒要長。