一、TCP/IP概念模型與OSI參考模型對比
OSI參考模型只是一個理想的概念,分為7層,從最底層的物理層、鏈路層、網絡層、傳輸層、會話層、表示層、應用層,但是TCP/IP的概念模型一般分為四層,即鏈路層、網絡層、傳輸層、應用層。
OSI中的物理層和鏈路層被歸為鏈路層,網絡層和傳輸層不變,最后三層統稱應用層。
在具體實現中,一般都是TCP/IP模型,分成四層:應用層、傳輸層、網絡層、鏈路層
1.TCP/IP協議并不是必須從應用層->傳輸層->網絡層的。
這里的ping命令其實就沒有經過傳輸層,而是直接從應用層到了網絡層
2.TCP和UDP的區別
- 1、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的,即發送數據之前不需要建立連接
- 2、TCP提供可靠的服務。也就是說,通過TCP連接傳送的數據,無差錯,不丟失,不重復,且按序到達;UDP盡最大努力交付,即不保證可靠交付
Tcp通過校驗和,重傳控制,序號標識,滑動窗口、確認應答實現可靠傳輸。如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。 - 3、UDP具有較好的實時性,工作效率比TCP高,適用于對高速傳輸和實時性有較高的通信或廣播通信。
- 4、每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信
- 5、TCP對系統資源要求較多,UDP對系統資源要求較少。
TCP連接通過三次握手確保連接的可靠性。
3.TCP特性
- 面向連接的
- 可靠性
- RTT(往返時延,Round-Trip Time)和RTO(重傳超時,Retransmission TimeOut)
- 數據排序
- 流量控制
- 全雙工
流量控制:滑動窗口,其實很簡單,就是每次tcp傳輸過程中,server和client會攜帶一個滑動窗口大小,意味著此時它能一次接受多少數據,因為數據在客戶端和服務器之間是有緩存的,滑動窗口也就相當于對方告訴自己目前緩沖區的大小,不需要每次發一個數據包就回一個ACK,通過滑動窗口來進行簡單的擁塞控制。 - 發送方和接收方都會維護一個數據幀的序列,這個序列被稱為窗口
- 發送方的窗口大小由接收方確認
比如第一次客戶端向服務端發送了1000個數據,但是服務端處理不過來,則在確認應答的時候,告訴客戶端不需要一次發送那么多數據,比如發送500就可以了。這也可以調整大,比如變成3000
使用滑動窗口的目的:
(1)確保數據不丟失
如果發送的數據丟失了可以重新發送
(2)控制發送速度
控制發送速度,以免接收方的緩存不夠大導致溢出,同時控制流量也可以避免網絡擁塞
4.TCP/IP四層模型,網絡層和傳輸層有什么區別?網絡層的主要工作是什么?
網絡層負責ip數據報的產生以及ip數據包在邏輯網絡上的路由轉發。
網絡層只是根據網絡地址將源結點發出的數據包傳送到目的結點(點到點),其主要任務是:通過路由選擇算法,為報文或分組通過通信子網選擇最適當的路徑。該層控制數據鏈路層與傳輸層之間的信息轉發,建立、維持和終止網絡的連接。具體地說,數據鏈路層的數據在這一層被轉換為數據包,然后通過路徑選擇、分段組合、順序、進/出路由等控制,將信息從一個網絡設備傳送到另一個網絡設備。
傳輸層提供端到端通信服務層次,提供可靠及非可靠連接,TCP和UDP。
傳輸層則負責將數據可靠地傳送到相應的端口(端到端),傳輸層提供了主機應用程序進程之間的端到端的服務。傳輸層利用網絡層提供的服務,并通過傳輸層地址提供給高層用戶傳輸數據的通信端口,使高層用戶看到的只是在兩個傳輸實體間的一條端到端的、可由用戶控制和設定的、可靠的數據通路。
二、TCP連接的三次握手
第一次握手
建立連接。客戶端發送連接請求報文段,將SYN位置為1,Seq序列號(Sequence Number)設置為x(系統隨機生成的);然后,客戶端進入SYN_SEND狀態,等待服務器的確認;
第一次握手,就是客戶端向服務器發送一個請求連接的報文,等待服務器確認,客戶端進入SYN_SEND狀態。
第二次握手
服務器收到SYN報文段。服務器收到客戶端的SYN報文段,需要對這個SYN報文段進行確認,設置Ack確認序列號(Acknowledgment Number)為x+1(Sequence Number+1),這個是Ack確認序列號,確認序列號都是為收到的報文的序列號+1得到的;同時,自己自己還要發送SYN請求信息,將SYN標志位置為1,并且將ACK標志位也置為1,Seq序列號(Sequence Number)為y(Seq為y,Seq系統隨機生成的);服務器端將上述所有信息放到一個報文段(即SYN+ACK報文段)中,一并發送給客戶端,此時服務器進入SYN_RECV狀態;客戶端進入ESTABLISHED狀態(established)。這是服務端請求與客戶端建立連接
第二次握手,就是服務器收到客戶端的報文段,對報文確認,然后服務器向客戶端發送一個SYN+ACK報文請求信息,服務器進入SYN_RECV狀態。這是服務端請求與客戶端建立連接
第三次握手
客戶端收到服務器的SYN+ACK報文段,檢查服務端發送過來的報文段ACK標志位是否為1,ack確認序列號是否為x+1。如果正確,然后將Ack確認序列號(Acknowledgment Number)設置為y+1,這個y是客戶端收到服務器端發送過來的報文的序列號y,將ACK標志位置為1,向服務器發送ACK報文段。這個報文段發送完畢以后,服務端接收到報文,檢查ACK標志位是否為1,且ack確認序列號是否為y+1,如果正確則連接建立成功,此時客戶端和服務器端都進入ESTABLISHED狀態,完成TCP三次握手。第三次握手時,客戶端發送給服務端的報文的的SYN標志位為0
第三次握手,是客戶端回應服務器的ACK報文信息,向服務器發送一個確認。
為什么要進行三次握手
為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。其實就是為了解決可靠性。三次握手發送的報文段都會有一個序號,三次握手就是為了交換TCP的初始序號,即客戶端發一個Seq=X,服務端就發送確認信號Ack為X+1。客戶端發送的連接,并不是先發的就先到,所以要避免混亂就需要通過序號和確認序號。三次握手,其實就是客戶端和服務端都需要將自己的初始序列號告訴對方,并且收到對方的確認信息。
TCP是面向連接的,所以需要雙方都確認連接的建立。如果是兩次連接,那么客戶端與服務端建立了連接,但是服務端向客戶端進行連接的時候,服務端就無法收到客戶端的確認信息,這樣服務端與客戶端的連接就沒有建立。
這里的初始序列號,那么下次進行通信的時候,就是從該初始序列號加上當前要發送的數據的長度,比如客戶端的初始序列號seq=500,要發送500bytes字節數據,那么下一次客戶端要發送的數據的序列號就是從511開始
三次握手的過程就是通信雙方互相告知初始序列號的值,并且確認對方已經收到了初始序列號值的一個步驟。
如果只進行兩次握手,至多只有連接發起方的初始序列號能被確認,而服務端的初始序列號并不能被客戶端確認,這樣客戶端就無法知道服務端的初始序列號,則無法正常接收對應的數據序列。
防止服務器端因為接收了早已失效的連接請求報文從而一直等待客戶端請求,從而浪費資源
- “已失效的連接請求報文段”的產生在這樣一種情況下:Client發出的第一個連接請求報文段并沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達server。
- 這是一個早已失效的報文段。但Server收到此失效的連接請求報文段后,就誤認為是Client再次發出的一個新的連接請求。
- 于是就向Client發出確認報文段,同意建立連接。
- 假設不采用“三次握手”:只要Server發出確認,新的連接就建立了。
- 由于現在Client并沒有發出建立連接的請求,因此不會向Server發送數據。
- 但Server卻以為新的運輸連接已經建立,并一直等待Client發來數據。>- 這樣,Server的資源就白白浪費掉了。
如果不采用三次握手,那么服務端接收一個早已經失效的報文并且確認,此時就會認為連接已經確認,但是因為客戶端這個時候并沒有發送一個有效的連接報文,而是服務端接收了一個失效的連接報文,這樣就可能客戶端認為沒連接,而服務端認為客戶端已經連接,造成服務端在等待客戶端發來的數據,導致服務端的資源浪費。
因為tcp是全雙工,為保證傳輸的可靠性,需要給每次傳輸的數據段添加序號,那么初始的序列號就是tcp三次握手真正的意義所在,而為了確保交換雙方的初始序號,最少需要三次才行
全雙工、半雙工、單工的解釋
全雙工:客戶端能給服務端發數據,服務端同時也可以給客戶端發數據
半雙工:客戶端給服務端發數據的時候,服務端只能接收;服務端接收完成之后,可以給客戶端發,但是這個時候客戶端就不能給服務端發
單工:只能客戶端給服務端發
TCP連接是全雙工的。
三次握手的漏洞
SYN洪泛攻擊:通過網絡服務所在的端口發送大量偽造原地址的攻擊報文,發送到服務端,造成服務端上的半開連接隊列被占滿,從而阻止其他用戶進行訪問。
原理:攻擊者客戶端利用偽造的IP地址向服務端發出請求(第一次握手),而服務的響應(第二次握手)的報文將永遠發送不到真實的客戶端,服務端在等待客戶端的第三次握手(永遠都不會有),服務端在等待這種半開的連接過程中消耗了資源,如果有成千上萬的這種連接,主機資源將耗盡,從而達到攻擊的目的。
解決的方案:
- 無效連接監控釋放
- 延緩TCB分配方法
- 防火墻(最好的方案)
SYN洪泛攻擊,一般服務端向客戶端發起應答請求的時候,是需要客戶端的ip,而洪泛攻擊就是偽造這個ip,往服務端發送第一次握手的數據,由于這第一次握手的客戶端ip是偽造的,那么服務端往客戶端進行第二次握手的時候由于客戶端ip是偽造的,則第二次握手就沒有結果,所以容易讓服務器被拖累,造成死機等問題。
什么時候可以給服務端發送數據?
其實當客戶端收到服務端的確認報文之后和請求建立連接的握手之后,向服務端發送第三次連接的時候,就可以帶有數據發送給服務端。因為三次握手只需要交換完了初始序列號之后就可以發送數據了。
最早可以給服務端發送數據,必須是在第三次握手的時候,由客戶端向服務端發送服務端連接的確認信息。
但是如果TCP三次握手連接成功之后,雙方一直不發送數據,那么在一定時間之后,TCP連接就會斷開,那么下次就需要重新進行連接
總結
從三次握手,可以總結看出,每次確認的確認序列號都是為收到的報文的序列號+1,SYN是在第一次和第二次的時候為1,ACK是在第二次和第三次的時候為1。
第一次SYN為1是為了讓服務器端確認,第二次為1是因為這個值需要客戶端來修改,ACK第二次為1是為了讓客戶端確認,第三次為1,是為了讓服務器端確認來進行連接。
Socket的三次握手
這里要注意Socket的connect()和accept()函數分別在三次握手的第幾次后返回?
connect在第二次握手,accept在第三次握手。
第一次握手時,創建連接,connect處于阻塞狀態,等待服務器accept,第二次握手成功,connect從阻塞返回,accept同樣的需要收到客戶端ack以后才從阻塞返回,連接建立完成。在accept接收到客戶端發送過來的第一次握手報文的時候,此時accept是處于阻塞狀態,并且返回一個確認信息和請求連接信息給客戶端,客戶端connect接收到后,返回信息給服務端,accept等到接收到客戶端返回過來的這個報文信息后,就會返回。
這個過程,其實可以認為是客戶端在第一個握手的時候調用connect視圖連接服務端,這個時候客戶端因為connect處于阻塞狀態,等待服務端的accept返回,第二次握手的時候,服務端返回信息,客戶端接收到之后,connect就會從阻塞狀態返回,然后向服務端發送ack確認請求進行第三次握手,當服務端收到確認信息之后,accept就會從阻塞狀態返回。
accept是在發送第二次握手報文的時候,進入阻塞狀態。connect是客戶端在發送第一次握手報文的時候進入阻塞狀態。
三、TCP連接的四次揮手
第一次揮手
主機1(可以使客戶端,也可以是服務器端),設置Sequence Number,向主機2發送一個FIN報文段(其實就是標志位FIN=1),此時也會發送一個seq序列號,該序列號的值是隨機的,比如是x;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了;發送FIN包
第二次揮手
主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段,ACK標志位為1,Acknowledgment Number為Sequence Number加1,即確認序列號ack=x+1;主機1收到主機2的應答報文后,進入FIN_WAIT_2狀態;主機2告訴主機1,我“同意”你的關閉請求;此時主機2進入CLOSE_WAIT狀態,此時與后面的CLOSED狀態還是有區別,服務端此時還沒有真的關閉。服務端進入CLOSE_WAIT狀態,表示當前自己是半關閉狀態,即對端已經沒有數據發送給自身,自身不需要接收數據了,但是自身與對端之間的連接還并沒有關閉,因為此時服務端還可能有數據發送給客戶端,還與客戶端保持連接。需要服務端向客戶端發起第三次揮手,告訴客戶端需要關閉服務端與客戶端之間的連接,然后客戶端確認之后,服務端才會進入CLOSED狀態
第三次揮手
主機2向主機1發送FIN報文段(即標志位FIN=1),并且發送一個序列號seq,序列號的值是隨機的,比如seq=y,并且還會發送一個確認序列號,該確認序列號其實是與第二次分手時的確認序列號一直,即ack=x+1,請求關閉連接,同時主機2進入LAST_ACK狀態;發送FIN包,服務端進入LAST_ACK狀態,是要等待客戶端的確認包
第四次揮手
主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段(標志位ACK=1),并且發送序列號,該序列號其實就是與第三次分手時的確認序列號一直,即seq=x+1,并且發送一個確認序列號,該確認序列號為第三次分手時的序列號+1,即ack=y+1,然后主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段以后,就關閉連接,進入CLOSED狀態;此時,主機1等待2MSL后依然沒有收到回復,則證明Server端已正常關閉,那好,主機1也可以關閉連接了,進入CLOSED狀態。
比如:當主機1發送關閉請求,并且主機2確認了該關閉請求后,主機1不能發送數據,但是可以繼續接收數據。只有當主機2發送了關閉請求,并且主機1確認關閉進入CLOSED狀態后,主機1才不能接收數據。
1.為什么要四次分手
TCP協議是一種面向連接的、可靠的、基于字節流的運輸層通信協議。TCP是全雙工模式,這就意味著,當主機1發出FIN報文段時,只是表示主機1已經沒有數據要發送了,主機1告訴主機2,它的數據已經全部發送完畢了;但是,這個時候主機1還是可以接受來自主機2的數據;當主機2返回ACK報文段時,表示它已經知道主機1沒有數據發送了,但是主機2還是可以發送數據到主機1的;當主機2也發送了FIN報文段時,這個時候就表示主機2也沒有數據要發送了,就會告訴主機1,我也沒有數據要發送了,之后彼此就會愉快的中斷這次TCP連接。
全雙工:其實就是客戶端可以向服務端發送,服務端也可以同時向客戶端發送,是有兩條連接。
揮手要四次:主要是客戶端和服務端都需要分別關閉請求,而關閉請求發送出去都需要接收到對方的同意,這樣兩個關閉請求,兩個同意就四次揮手。
四次揮手有可能是服務端發起的,也有可能是客戶端發起的。
四次揮手是有可能變成三次的。第二次跟第三次可以合并為一個一次性發送給客戶端。但是這樣的情況比較小。在主機2發送確認報文給主機1的時候,當主機2沒有額外的報文發送給主機1了,那么第二次和第三次分手有可能合并。
而FIN報文也是有可能與數據一起發送,比如主機1發送一個數據給主機2,此時該數據是最后一次發送,那么也有可能同時發送FIN報文。
但是第一次分手也有可能隨著最后一次數據一起發送
2.四次揮手的狀態轉移:
客戶端向服務端發送第一次揮手:客戶端從established->FIN_WAIT_1狀態
服務端向客戶端發送第二次揮手:客戶端從FIN_WAIT_1->FIN_WAIT_2狀態
服務端向客戶端發送第三次揮手:服務端從established->LAST_ACK狀態,
客戶端向服務端發送第四次揮手:客戶端從FIN_WAIT_2->TIME_WAIT狀態,此時客戶端必須在此停留超過2MSL時間之后,客戶端就默認斷開。一來一回最大的時間
為什么是要兩個MSL時間?
- 保證TCP協議的全雙工連接能夠可靠關閉
- 保證這次連接的重復數據段從網絡中消失
解釋一:
如果在兩個MSL時間內,比如第四次揮手丟了,那么對方就需要在超時后重發第三次揮手的FIN包,客戶端接收到服務端的重發的FIN包之后,可以再發一個ACK確認包。如果服務端沒收到客戶端最后發過來的這個ACK確認包,那么這一來一回,即客戶端接收一個重發的FIN包,又重發一個ACK確認包給服務端,這樣的一來一回,就是兩個MSL時間。
客戶端在兩個MSL時間內,是不能使用的,需要等到2MSL時間結束之后才可以繼續使用。
解釋二:
這里規定,在一端處于TIME_WAIT狀態的時候,其端口是不允許建立連接的。
如果Client直接CLOSED,而不在TIME_WAIT等待2*MSL時間,此時又有一個客戶端又再向Server發起一個新連接,我們不能保證這個新連接與剛關閉的連接的端口號是不同的。也就是說有可能新連接和老連接的端口號是相同的。一般來說不會發生什么問題,但是還是有特殊情況出現:假設新連接和已經關閉的老連接端口號是一樣的,如果前一次連接的某些數據仍然滯留在網絡中,這些延遲數據在建立新連接之后才到達Server,由于新連接和老連接的端口號是一樣的,又因為TCP協議判斷不同連接的依據是socket pair,于是,TCP協議就認為那個延遲的數據是屬于新連接的,這樣就和真正的新連接的數據包發生混淆了。所以TCP連接還要在TIME_WAIT狀態等待2倍MSL,這樣可以保證本次連接的所有數據都從網絡中消失。即前一個連接的延遲數據包,要到達服務端,然后服務端要響應該延遲數據,這樣的一來一回才會最終消失數據段。
MSL:Max Seqment Lifetime,報文最大生存時間(RFC定義為2分鐘,大部分操作系統只有30秒)
TIME_WAIT時間,一般是1~4分鐘。
四次分手發起者
其實分手的主動發起者并不一定是客戶端,客戶端和服務端都是可以主動發起分手。