前言:
TCP協議是計算機的基礎,他本身是一個非常非常復雜的協議。
本文只是蜻蜓點水,將從網絡基礎以及TCP的相關概念介紹開始,之后再將三次握手,四次揮手這些內容來闡述。
最后介紹一些常見問題,并給出解答。
?網絡分層
在實際的網絡中,我們是四層網絡結構:
網絡傳輸層
網絡傳輸層負責最底層的底層鏈路連接。兩臺主機之間進行互聯,基于網線的物理硬件上的協議。在這個側面,主機與主機之間只認得硬件mac編碼。并不認識IP。
網絡層
IP就是在網絡層出現的,就像網絡上,每個機器的地址。網絡層可以理解為快遞,它的職能就是根據地址(IP),把東西從一個地方運送到另一個地方
傳輸層
傳輸層相比于網絡層最大的不同就是引入了端口的概念。網絡層只管發送地址和目的地址。但是發送主機上有可能有多個程序和同一個接收主機進行傳輸數據,怎么區分這多個程序呢?就引入了端口的概念。(發送IP地址,發送端口,接收IP地址,接收端口)四元組標示了一個主機的程序到另一個主機程序的唯一標示。傳輸層的職能,就是維護這個四元組。
其實傳輸層還有一個職能是定義發送方和接收方基本處理包的行為。上面說到網絡層就相當于郵件運輸工,它只負責把一包東西從一個地方放到另外一個地方,但是,這包東西是否送達了,送達之后接收方又有什么行為。這些都可以在傳輸層進行定義。注意,這里說的是可以,你也可以在傳輸層布不管這些,只做簡單的基本封裝四元組,比如UDP
應用層
指定到主機端口了,接下來就是應用層干活了,可以傳文件,傳文本。應用層就是實際上對具體的程序之間的交互功能進行定義的層。
TCP協議
TCP(Transmission Control Protocol) 傳輸控制協議.TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接。
協議結構如下:
這里就不全部都講了,主介紹一部分:
Source Port和Destination Port
這兩個字段表示發送地址和目的地址的端口號,發送地址的IP和目的地址的IP是在IP協議頭中
Sequence number(順序號碼) Acknowledge number(確認號碼)
TCP的任意一端(不管是客戶端還是服務端),可以發送數據,也可以接受數據。那么發送序列號就是Seqence Number,接受序列號就是Acknowledgement Number。
其次,序列號是用來標志包的順序的。網絡中包由于網絡問題,接受到的并不是按順序到達的,接受端可以根據這個序列號來進行組裝。
比如:
給服務端發送8000字節的數據,順序號從10000開始,分成4個包發送,那么它們的標識就是12000,14000,16000,18000。
如下圖所示,由于網絡問題,最先到達的是序號為14000,但是服務端可以根據這些包的序號進行拼接,拼成完整的包。
Data offset和Reserved
由于tcp頭可能是不固定大小的(因為存在可選字段),所以需要有這個值來表示當前這個包的tcp頭有多大。
Reserved就是保留字段
位碼TCP標志位
就是下圖中的紅框的內容
SYN(synchronous建立聯機):建立連接,發送一方告知另外一方,請求建立連接
ACK(acknowledgement 確認):該包中有回復信息
PSH(push傳送):該包中有傳輸信息
FIN(finish結束):結束位,發送一方告知另外一方,請求中斷連接
RST(reset重置):重置位,這個包是用來要對方重置連接
URG(urgent緊急):緊急位,已經建議棄用
?
握手與揮手:
?有了上面的基礎知識,相信下面的三次揮手和四次握手理解起來也不會費勁的。
下圖是三次握手的過程:
三次握手過程說明:
TCP服務器進程先創建傳輸控制塊TCB(存儲了每一個連接中的一些重要信息,如:TCP連接表,到發送和接收緩存的指針,到重傳隊列的指針,當前的發送和接收序號,等),準備接受客戶進程的連接請求。然后服務器進程就處于LISTEN(收聽)狀態,等待客戶的連接請求。如有,即作出相應。
第一次握手:
客戶端Client向服務端Server發起建立連接請求。客戶端會發送位碼SYN(請求建立連接),以及序列號x(seq=x),TCP規定,SYN報文段(即SYN=1的報文段)不能攜帶數據,但要消耗掉一個序號。這時,TCP客戶進程進入SYN-SENT(同步已發送)狀態。
第二次握手:
服務端Server接受到請求報文段之后。如同意建立連接,則向客戶端發送確認消息。在確認報文段中應把SYN位和ACK位都置1,確認號是ack=x+1,同時也為自己選擇一個初始序號seq=y。注意。這個報文段也不能攜帶數據,但同樣要消耗掉一個序號。這時服務端進程進入SYN-RCVD(同步收到)狀態。
第三次握手:
客戶端Client收到服務端Server的確認后,還要向服務端給出確認。確認報文段的ACK置1,確認號ack=y+1,而自己的序號seq=x+1。這時,TCP連接已經建立,客戶端進入ESTABLISHED(已連接狀態)。當服務端收到客戶端的確認之后,也進入ESTABLISHED狀態。
總結:
客戶端在三次握手中,狀態的轉變是:CLOSED->SYN_SEND->ESTABLISHED
服務端在三次握手中,狀態的轉變是:CLOSED->LISTENED->SYN_RCVD->ESTABLISHED
問題一:為什么不可以兩次握手,為什么客戶端還要再發送一次確認?
答:消除舊有連接請求的SYN消息對新連接的干擾,同步連接雙方的序列號和確認號并交換TCP 窗口大小信息。
比如說這種異常情況:客戶端發出的第一個連接請求報文段并沒有丟失,而是在某些網絡結點長時間滯留了,以致延誤到連接釋放以后的某個時間才到達服務端。本來這是一個早已失效的報文段。但服務端收到此失效的連接請求報文段后,就誤以為是客戶端又發出一次新的連接請求。于是就向客戶端發出確認報文段,同意建立連接。假定不采用三次握手,那么只要服務端發出確認,新的連接就建立了。
問題二:什么是SYN攻擊?如何檢測它?
?? 在三次握手過程中,服務器發送SYN-ACK之后,收到客戶端的ACK之前的TCP連接稱為半連接(half-open connect).此時服務器處于Syn_RECV狀態.當收到ACK后,服務器轉入ESTABLISHED狀態.
Syn攻擊就是 攻擊客戶端
在短時間內偽造大量不存在的IP地址,向服務器不斷地發送syn包,服務器回復確認包,并等待客戶的確認,由于源地址是不存在的,服務器需要不斷的重發直
至超時,這些偽造的SYN包將長時間占用未連接隊列,正常的SYN請求被丟棄,目標系統運行緩慢,嚴重者引起網絡堵塞甚至系統癱瘓。
? Syn攻擊是一個典型的DDOS攻擊。檢測SYN攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊.在Linux下可以如下命令檢測是否被Syn攻擊:
netstat -n -p TCP | grep SYN_RECV
一般較新的TCP/IP協議棧都對這一過程進行修正來防范Syn攻擊,修改tcp協議實現。主要方法有SynAttackProtect保護機制、SYN cookies技術、增加最大半連接和縮短超時時間等.
但是不能完全防范syn攻擊。
四次揮手過程說明:
?在客戶端和服務端已經建立連接的情況下,需要四次揮手來斷開連接。如下圖所示:
第一次揮手:
客戶端發送一個FIN=1的報文段和順序號為u(seq=u)的請求關閉消息(客戶端沒有消息要發給你了,我準備關閉連接了,但是如果你還有數據沒有發送完成,則不必急著關閉Socket,可以繼續發送數據。所以你先發送ACK)。客戶端進入FIN-WAIT-1狀態,等待服務端的FIN報文段。
第二次揮手:
服務端收到客戶端的FIN報文段,會發送一個確認報文段ACK=1,以及確認序列號ack=u+1,還有自己的序列號seq=v(告訴客戶端,我已經收到你的請求關閉消息,但是我還沒準備好,請繼續等待),服務單進入CLOSE-WAIT階段,此時服務端還未關閉。
第三次揮手:
服務端向客戶端發送FIN=1報文段(告訴Client端,好了,我這邊數據發完了,準備好關閉連接了),ACK=1,序列號seq=w,ack=u+1,服務端進入LAST-ACK狀態
第四次揮手:
客戶端收到服務端發來的FIN=1報文段,給服務端發送ACK=1報文段,序列號seq=u+1,ack=w+1的消息。這時客戶端就可以關閉連接了,但是他還是不相信網絡,怕Server端不知道要關閉,所以發送ACK后進入TIME_WAIT狀態,如果Server端沒有收到ACK則可以重傳
,客戶端等待了2MSL后依然沒有收到回復,客戶端關閉。服務端也關閉。
總結:
客戶端在四次揮手中的狀態變化是:ESTABLISHED -> FIN-WAITED-1 -> FIN-WAITED-2 -> TIME-WAITED -> CLOSED
服務單在四次揮手中的狀態變化是:ESTABLISHED -> CLOSE-WAITED LAST-ACK -> CLOSED
?
問題一:為什么在第四次回收后會有2個MSL的延時?
首先了解MSL,Maximum Segment Lifetime,最大報文生存時間,2個MSL是報文段發送和接受的最長時間。
假定網絡不可靠,那么第四次發送的ACK可能丟失,即服務端無法收到這個ACK,如果服務端收不到這個確認ACK,服務端會定時向客戶端端重復發送FIN,直到服務單端收到客戶端的確認ACK。所以這個2MSL就是用來處理這個可能丟失的ACK的。
問題二:為什么握手只要三次,揮手卻需要四次?
在TCP連接中,服務端SYN和ACK向客戶端發送是一次性發送的,而在斷開連接的過程中,服務端向客戶端發送的ACK和FIN是分兩次發送的。因為在服務端接受到客戶端的FIN后,服務端還有數據要傳輸的話,所以先發送ACK,等服務端處理完自己的事情后就可以發送FIN斷開連接了。
下篇預告:
TCP長連接與短連接,與Socket的聯系
參考鏈接: