源端口和目的端口: 各佔2個字節,分別寫入源端口號和目的端口號(TCP報文須要的是端口號,往下封裝會在IP報文中添加上源IP和目的IP)服務器
序號: 4個字節,[0-了2^32-1]一共有2^32個序號,由於TCP是面向字節流;在一個TCP鏈接中傳送的字節流中的每個字節都按順序編號;整個要傳送的字節流的起始序號必須在鏈接創建的時候設置(也就是一開始三次握手的時候發送的SYN包中的seq字段部分)。TCP報文中的首部的序號字段則是本報文段所發送的數據的第一個字節的序號。網絡
確認號:ack;4個字節,表示的是指望收到對方下一個報文段的第一個數據字節的序號;好比說,B正確的收到了A發送過來的一個報文段,其序號字段值爲501,且數據的長度爲200字節(501-700),這代表B正確受到了A發送的到序號700爲止的數據,所以B但願收到A的下一個數據序號是701;因此ack=701。spa
總之,若確認號爲N,則代表到序號N-1爲止的全部數據已經正確接收。
.net
確認ACK:僅當ACK=1時,確認號字段(ack)有效,當ACK=0的時候,確認號字段無效。TCP規定,在鏈接創建後全部傳送的報文段的ACK都置1。xml
終止FIN:用來釋放一個鏈接,當FIN=1的時候代表此報文段的發送方的數據已經發送完畢,而且要求釋放鏈接。blog
窗口:佔2個字節,值在[0-2^16-1]之間的整數,指的是發送本報文段的一方的接收窗口(而不是本身的發送窗口),窗口值主要是用來告訴對方:從本報文段首部中的確認號算起,我目前的容許對方發送的數據量——主要是用來解決防止發送方發送數據過快而來不及接收,總之窗口值做爲接收方讓發送方設置其發送窗口大小的依據。進程
(ps:圖片來自https://blog.csdn.net/qzcsu/article/details/72861891這位大佬的博客)圖片
TCP服務器進程先建立傳輸控制塊TCB,準備接受客戶端進程的鏈接請求,而後服務器進程就處於LISTEN(監聽)狀態,等待客戶端的鏈接請求。資源
TCP客戶端進程也是先建立傳輸控制塊TCB,而後向服務器端發送鏈接請求報文。開發
第一次握手:
客戶端發送SYN包(SYN=1,seq=x)給服務器端,等待服務器的確認,進入SYN_SEND(同步已發送)狀態。
解釋:第一次握手客戶端發送的SYN包中,SYN是同步序列編號,須要設置爲1,seq是用於創建鏈接以後通訊所用的,表示的是創建鏈接後要傳輸的數據的起始序號,TCP規定,雖然第一次握手發送的SYN包沒有攜帶數據,可是也要佔用一個序號,即客戶端發送數據的時候只能用x+1開始發送。
第二次握手:
服務器接收到客戶端發送的SYN包,若是贊成創建鏈接,那麼就發送了一個確認報文段(ACK=1,ack=x+1,SYN=1,seq=y),進入SYN_RECV(同步收到)狀態。
解釋:第二次握手中的ACK=1是爲了讓確認號字段ack有效,而ack=x+1代表的是服務器方已經成功接收到客戶端發送的到x爲止(包括x)的全部數據;而且但願下一次收到客戶端發送過來的數據是從x+1開始;同時因爲是全雙工的通訊,服務器端設置SYN=1,seq=y,用於創建鏈接後的發送數據的起始序號;TCP規定:雖然這份確認報文段不攜帶數據,可是也要佔用一個序號的位置。
第三次握手:
客戶端接收到服務器端發送的確認報文段,而且向服務器發送ACK確認報文段(seq=x+1,ack=y+1,ACK=1),此時,TCP鏈接創建,客戶端進入ESTABLISHED(已創建鏈接)狀態。
解釋:第三次握手客戶端發送了ACK確認報文(ACK=1,ack=y+1,seq=x+1),ACK=1和ack=y+1表示對服務器發送的確認報文段的一個確認,同時但願下次收到的數據的起始序號從y+1開始,TCP規定:本次的ACK確認報文段能夠攜帶數據,可是若是不攜帶數據則不消耗序號。
**爲了確保通訊雙方的發送信息和接收信息的能力沒問題。
假設客戶端爲A,服務器端爲B
1.一開始A發送SYN包給B,B收到了A發送的SYN包
---->B本身就會以爲,本身的接收信息能力沒問題。
2.B發送確認報文段給A,而且A收到B發送的包
---->A收到了包以後,首先由於B不會無故端發送信息給A,A就會知道剛剛本身成功發送了信息B,說明A本身的發送能力沒問題,其次是A如今接收到了B的包,證實A本身的接收能力也沒問題。可是這個時候B並不知道本身的發送能力怎麼樣,因此須要再A發送多一次進行多一次握手才能夠。
3.A再發送ACK包給B
---->B目前還不知道本身的發送能力怎麼樣,直到A發送了確認包回來,那麼就說明B本身的發送能力沒問題。
好~~開心的通訊吧~~
(ps:圖片來自https://blog.csdn.net/qzcsu/article/details/72861891這位大佬的博客)
1.客戶端進程發出鏈接釋放報文(FIN包),而且中止發送數據。釋放數據報文首部,FIN=1,其序列號爲seq=u(等於前面已經傳送過來的數據的最後一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即便不攜帶數據,也要消耗一個序號。
2.服務器收到鏈接釋放報文,發出確認報文,ACK=1,ack=u+1(表示對u+1以前的發送的數據進行一個確認),而且帶上本身的序列號seq=v(由於因爲是客戶端提出的關閉鏈接;可是服務器端可能還有數據沒有發送完),此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間
3.客戶端收到服務器的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文(在這以前還須要接受服務器發送的最後的數據)。
4.服務器將最後的數據發送完畢後,就向客戶端發送鏈接釋放報文,FIN=1,ack=u+1,因爲在半關閉狀態,服務器極可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認(w-v獲得的就是服務器方在這段時間發送的數據的總量。)
5.客戶端收到服務器的鏈接釋放報文後,必須發出確認,ACK=1,ack=w+1,而本身的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP鏈接尚未釋放,必須通過2∗∗MSL(最長報文段壽命)的時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。
6.服務器只要收到了客戶端發出的確認,當即進入CLOSED狀態。一樣,撤銷TCB後,就結束了此次的TCP鏈接。能夠看到,服務器結束TCP鏈接的時間要比客戶端早一些。
MSL(Maximum Segment Lifetime),TCP容許不一樣的實現能夠設置不一樣的MSL值。
第一,保證客戶端發送的最後一個ACK報文可以到達服務器,由於這個ACK報文可能丟失,站在服務器的角度看來,我已經發送了FIN+ACK報文請求斷開了,客戶端尚未給我回應,應該是我發送的請求斷開報文它沒有收到,因而服務器又會從新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接着給出迴應報文,而且會重啓2MSL計時器。
第二,防止相似與「三次握手」中提到了的「已經失效的鏈接請求報文段」出如今本鏈接中。客戶端發送完最後一個確認報文後,在這個2MSL時間中,就可使本鏈接持續的時間內所產生的全部報文段都從網絡中消失。這樣新的鏈接中不會出現舊鏈接的請求報文。
爲何創建鏈接是三次握手,關閉鏈接確是四次揮手呢?
創建鏈接的時候, 服務器在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。
而關閉鏈接時,服務器收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,而本身也未必所有數據都發送給對方了,因此己方能夠當即關閉,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送,從而致使多了一次。
TCP還設有一個保活計時器,顯然,客戶端若是出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會從新復位這個計時器,時間一般是設置爲2小時,若兩小時尚未收到客戶端的任何數據,服務器就會發送一個探測報文段,之後每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉鏈接。
參考:網上某位大佬的博客,路徑爲:https://blog.csdn.net/qzcsu/article/details/72861891;侵權請告知刪除。