1.什麼是鏈接?編程
TCP協議屬於運輸層協議,運輸層協議是在端系統中,而不是在路由器中實現的,因此,這種鏈接不是一條電路,它的鏈接狀態,徹底保存在兩個端系統中.中間的網絡元素,包括路由器和鏈路層交換機這些網絡元素不會維持TCP的鏈接狀態.一個進程往另外一端的某進程發送數據以前,必須先相互握手,即它們必須相互發送某些預備報文段,以創建確保數據傳輸的參數.緩存
2.鏈接的三次握手過程安全
第一次握手:客戶端首先向服務器端發送一個被稱爲SYN的特殊TCP報文段,此報文段的SYN比特位被置爲1,另外客戶端會隨機選擇一個初始序號client_seq並將此編號放置在TCPSYN報文段的序號字段中併發送給服務器服務器
第二次握手:服務器收到此TCPSYN報文段後,提取出SYN字段,併爲該鏈接分配TCP緩存和變量,而後向客戶端發送容許鏈接的報文段SYNACK,此報文段中SYN比特位被置爲1,而後該報文段的確認號字段被置爲client_seq+1,序列號置爲server_seq網絡
第三次握手:客戶端在收到SYNACK以後,客戶端也要給該鏈接分配緩存和變量,而後向服務器發送另外一個報文段,這最後一個報文段對服務器的容許鏈接的報文段進行了確認(將確認號置爲server_seq+1).同時,由於鏈接已創建 ,SYN標誌爲此時爲0併發
要注意的是,以上三次握手過程當中,在前兩個握手階段,都不含有應用層的任何數據,而在第三個階段中,可攜帶應用層的數據 .三次握手完成後,之後的每一個報文段,SYN比特位都被置爲0,實際上,只有握手過程當中的第一二次握手,SYN比特位才爲1.socket
三次握手過程圖標以下:函數
(TCP三次握手過程)server
3.鏈接的關閉blog
TCP鏈接須要三次握手,而關閉須要四次恢手,TCP鏈接的任一方都能主動發起關閉
a.A方向B方發送一個特殊的報文段,此報文段FIN標誌位被設爲1.此時,A方進入FIN_WAIT_1狀態,並關閉寫通道
b.B方收到A發來的帶有FIN標誌的報文段後,先發送ACK報文段,同時關閉讀通道(也就是說如今再也不從這個鏈接上讀取數據了,如今read會返回0),此時B將進入CLOSE_WAIT狀態,再發送一個FIN標誌位爲1的報文段
c.A方處於FIN_WAIT_1狀態時,收到B方發來的ACK確認報文後,進入FIN_WAIT_2狀態
d.A方處於FIN_WAIT_2狀態時,收到B方發來的帶有FIN標誌位爲1的報文段後,進入TIME_WAIT狀態,此狀態維持的時間與具體實現相關,通常爲2分鐘.通過等待後,鏈接正式關閉,全部資源將被釋放
主動發起方,在TIME_WAIT後,纔會完全關閉,被動關閉方,在對方的ACK到來後關閉
4.TCP的半關閉
TCP提供了鏈接的一端在結束它的發送後還能接收來自另外一端數據的能力,這就是所謂的半鏈接.當向對方發送一個FIN給另外一端時,就代表本方已結束髮送數據,但依然能夠接收另外一端發來的數據,直到對方也發來了FIN.也就是說,在FIN_WAIT_1-FIN_WAIT_2這一段時間內,都處於半關閉狀態.
服務器和客戶端應用程序判斷對方是否已經關閉鏈接的方法是:read調用返回0(收到結束報文段).socket網絡編程接口經過shutdown函數提供了對半關閉的支持.
5.CLOSE_WAIT狀態
當一方主動關閉鏈接時(經過close或shutdown系統調用向服務器發送結束報文段),另外一方經過返回確認ACK使鏈接進入CLOSE_WAIT狀態。這個狀態含義就是:等待主動關閉方應用程序關閉。一般,被動方也會當即給主動關閉方發送FIN報文段來關閉鏈接。
這將使鏈接轉移到LAST_ACK狀態 ,以等待主動關閉方對FIN報文段的最後一次確認,一旦確認完成,鏈接就完全關閉了。
6.TIME_WAIT狀態
主動關閉的一方,在收到對方發來的FIN後,並無直接進入CLOSED狀態,而是轉移到TIME_WAIT狀態.在這個狀態,主動關閉的一方要等待長爲2MSL(報文段最大生存時間)的時間,
才能徹底關閉.MSL是TCP報文段在網絡中的最大生存時間,RTF建議值是2min.
time_wait狀態存在的緣由有二:
a.可靠地終止TCP鏈接
b.保證讓遲來的TCP鏈接報文段有足夠的時間被識別並丟棄
對於第一個緣由,若是主動關閉方收到對方發來的FIN後,發送給被動關閉方的ACK沒有被正常收到,則被動關閉方會再次發送FIN,因此若是在TIME_WAIT狀態時,對方沒有再次發送FIN,則表示對方已經收到了ACK.已經正確關閉了.在Linux系統中, 一個TCP端口不能被同時打開屢次,當一個TCP鏈接處於TIME_WAIT狀態時,將沒法當即使用該鏈接佔用着的端口.反過來,若是不存在TIME_WAIT狀態,則應用程序可以當即創建一個和剛關閉的鏈接具備相同IP和端口的鏈接.這個鏈接可能會收到原來的鏈接的數據,這顯然不該該發生,這就是time_wait狀態存在的第二個緣由.
另外,TCP報文段的最大生存時間是MSL,因此堅持2MSL時間的TIME_WAIT狀態可以確保網絡上兩個傳輸方向上還沒有被接收到的,遲到的TCP報文段都已經消失.所以一個具備相同IP和端口的鏈接就能夠安全地創建,而絕對不會收到屬於原來鏈接的應用數據.
對於客戶端來講,一般不用擔憂上面的TIME_WAIT致使不能綁定對應端口的問題,由於客戶端通常使用系統自動分配的臨時端口號,而因爲隨機性,臨時端口號通常和程序上一次使用的端口號(還處於TIME_WAIT狀態的那個鏈接使用的端口號)不一樣,因此客戶端能夠當即重啓.而若是是服務器主動關閉鏈接後異常終止,則由於它老是使用一個相同的端口號,因此由於TIME_WAIT狀態將致使它不能當即重啓,不過能夠經過設置socket選項SO_REUSEADDR來強制進程當即使用TIME_WAIT狀態的鏈接佔用的端口.