TCP 連接建立的三次握手
1、先提出一個問題,可以不進行三次握手直接往服務(wù)端發(fā)送數(shù)據(jù)包嗎?
是不可以的,也是可以的;
1)不可以是因為現(xiàn)在的TCP連接標準和規(guī)范要求傳輸數(shù)據(jù)前先確認兩端的狀態(tài),有一端狀態(tài)不OK的話,發(fā)數(shù)據(jù)包有什么用呢;
2)說可以是站在網(wǎng)絡(luò)連接的角度,像 UDP 協(xié)議;
TCP,Transmission Control Protocol,傳輸控制協(xié)議,面向連接;
UDP,User Data Protocol,用戶數(shù)據(jù)報協(xié)議,面向數(shù)據(jù)包;
2、TCP三次握手

1)標志位、隨機序列號和確認序列號是在數(shù)據(jù)包的 TCP 首部里面;
2)幾個狀態(tài)是指客戶端和服務(wù)端連接過程中 socket 狀態(tài);
3)第一次握手,客戶端向服務(wù)端發(fā)送數(shù)據(jù)包,該數(shù)據(jù)包中 SYN 標志位為 1,還有隨機生成的序列號c_seq,客戶端狀態(tài)改為 SYN-SENT;
4)第二次握手,服務(wù)端接收到客戶端發(fā)過來的數(shù)據(jù)包中 SYN 標志位為 1,就知道客戶端想和自己建立連接,服務(wù)端會根據(jù)自身的情況決定是拒絕連接,或確定連接,還是丟棄該數(shù)據(jù)包;
拒絕連接,會往客戶端發(fā)一個數(shù)據(jù)包,該數(shù)據(jù)包中 RST 標志位為 1,客戶端會報 Connection refused;
丟棄客戶端的數(shù)據(jù)包,超過一定時間后客戶端會報 Connection timeout;
確定連接時會往客戶端發(fā)一個數(shù)據(jù)包,該數(shù)據(jù)包中 ACK 標志位為 1,確認序列號 ack=c_seq+1,SYN 標志位為 1,隨機序列號 s_seq,狀態(tài)由 LISTEN 改為 SYN-RCVD;
5)第三次握手,客戶端接收到數(shù)據(jù)包會做校驗,校驗ACK標志位和確認序列號 ack=c_seq+1,如果確定是服務(wù)端的確認數(shù)據(jù)包,改自己的狀態(tài)為 ESTABLISHED,并給服務(wù)端發(fā)確認數(shù)據(jù)包;
6)服務(wù)端接到客戶端數(shù)據(jù)包,會校驗ACK標志位和確認序列號 ack=s_seq+1,改自己的狀態(tài)為 ESTABLISHED,之后就可以進行數(shù)據(jù)傳輸了;
7)建立連接時的數(shù)據(jù)包是沒有實際內(nèi)容的,沒有應(yīng)用層的數(shù)據(jù);
8)建立連接之后發(fā)起的請求數(shù)據(jù)包,每個數(shù)據(jù)包都會封裝各層協(xié)議的頭部信息,標志位ACK為1,其他標志位變動;
9)網(wǎng)絡(luò)進程間的通信,一臺服務(wù)器內(nèi)部的進程間通信不用這樣;
3、TCP 連接三次握手抓包

三次握手底層邏輯
1、Socket
1)Socket 在 linux 系統(tǒng)中是一種特殊的文件,因為 linux 系統(tǒng)的理念就是【一切皆文件】,是系統(tǒng)內(nèi)核級的功能;
2)以上定義比較具體,可以抽象來理解,是一個內(nèi)核級的用于通信的功能層,包含一組接口函數(shù),這些函數(shù)實際就是操作 socket 文件句柄文件描述符;
一個 TCP 連接由四要素【源IP、源Port、目標IP、目標Port】唯一標識,也即 socket 由這四要素唯一確定;
一個 TCP 連接的建立也就是客戶端、服務(wù)端創(chuàng)建了相對應(yīng)的一對 socket,客戶端和服務(wù)端之間的通信也就是這對 socket 間的通信(物理層面是網(wǎng)卡在發(fā)送/接收比特流數(shù)據(jù));
3)一個服務(wù)與另一個服務(wù)建立連接,他們的端口是什么呢?
客戶端發(fā)出請求端口號是隨機的,服務(wù)端是進程監(jiān)聽的端口號;


2、socket 主要函數(shù)介紹


1、進程通信,一個進程只有一個監(jiān)聽 socket,connect socket 是針對一個客戶的一個連接的,有很多個; 2、connect 函數(shù)內(nèi)部在發(fā)起請求前會找系統(tǒng)隨機一個端口號; 3、連接建立后,客戶端發(fā)起請求傳輸數(shù)據(jù),服務(wù)端會直接交給 connect socket 處理,不會交給監(jiān)聽 socket 處理;
4、監(jiān)聽 socket 在處理客戶端請求時,如果此時其他客戶端發(fā)請求過來,監(jiān)聽 socket 是沒法處理的,此時系統(tǒng)會維護請求隊列由 backlog 參數(shù)指定;
全連接隊列(completed connection queue)
半連接隊列(incomplete connection queue)
Linux 內(nèi)核 2.2 版本之前,backlog 的大小等于全連接隊列和半連接隊列之和;
Linux 內(nèi)核 2.2 版本之后,backlog 的大小之和全連接隊列有關(guān)系:
半連接隊列大小由
/proc/sys/net/ipv4/tcp_max_syn_backlog 文件指定,可以開很大;
全連接隊列大小由
/proc/sys/net/core/somaxconn 文件和 backlog 參數(shù)指定,取兩個中的最小值;
Tomcat acceptCount 就是配置全連接隊列大小;

3、socket 函數(shù)在建立連接和數(shù)據(jù)傳輸?shù)拇蟾攀褂们闆r




4、TCP首部結(jié)構(gòu)


1)2的16次方等于 65536,所以系統(tǒng)中端口號的限制個數(shù)為 65536,一般1024以下端口被系統(tǒng)占用;
2)標志位這里是 6 個,還有其他標志位的,只是這 6 個標志位常用;
3)seq 序列號,ack 確認序列號,序列號在數(shù)據(jù)傳輸時分包用到。三次握手時 seq 序列號是隨機的,沒有實際意義;
4)TCP 包首部后面接著的是 IP 包首部,再緊接著的是以太網(wǎng)包首部,其實都是加 0101010101 二進制位;
幾個常用標志位,首先一個標志位占一個 bit 位,只能是二進制中的 1 或 0;
1)SYN,簡寫 S,請求標志位,用來建立連接。在TCP三次握手中收到帶有該標志位的數(shù)據(jù)包,表示對方想與己方建立連接;
2)ACK,簡寫【.】,請求確認/應(yīng)答標志位,用于對對方的請求進行應(yīng)答,對方收到含該標志位的數(shù)據(jù)包,會知道己方存在且可用。也會用在連接建立之后,己方發(fā)送響應(yīng)數(shù)據(jù)給對方的數(shù)據(jù)包中;
3)FIN,簡寫 F,請求斷開標志位,用于斷開連接。對方收到己方的含該標志位的數(shù)據(jù)包,就知道己方想與它斷開連接,不再保持連接;
4)RST,簡寫 R,請求復(fù)位標志位,因網(wǎng)絡(luò)或己方服務(wù)原因?qū)е掠袛?shù)據(jù)包丟失,己方接收到的數(shù)據(jù)包序列號與上一個數(shù)據(jù)包的序列號不銜接,那己方會發(fā)送含該標志位的數(shù)據(jù)包告訴對方,對方接收到含該標志位的數(shù)據(jù)包就知道己方要求它重新三次握手建立連接并重新發(fā)送丟失的數(shù)據(jù)包,一般斷點續(xù)傳會用到該標志位;
還有就是如果對方發(fā)過來的數(shù)據(jù)錯了,有問題,己方也會發(fā)送含該標志位的數(shù)據(jù)包;
5)PSH,簡寫 P,推送標志位,表示收到數(shù)據(jù)包后要立即交給應(yīng)用程序去處理,不應(yīng)該放在緩存中,read()/write() 都有緩存區(qū);
6)URG,簡寫 U,緊急標志位,該標志位表示 tcp 包首部中的緊急指針域有效,督促中間層盡快處理;
7)ECE,在保留位中;
8)CWR,在保留位中;
5、TCP 抓包





TCP 連接斷開的四次揮手

1)服務(wù)端會根據(jù)自身情況,沒有要處理的數(shù)據(jù)時會把第二次和第三次揮手合并成一次揮手,此時標志位 FIN=1 / ACK=1;
2)MSL 是 Maximum Segment Lifetime 縮寫,指數(shù)據(jù)包在網(wǎng)絡(luò)中最大生存時間,RFC 建議是 2分鐘;
詳細描述:
1)客戶端、服務(wù)端都可以主動發(fā)起斷開連接;
2)第一次揮手,客戶端向服務(wù)端發(fā)送含 FIN=1 標志位的數(shù)據(jù)包,隨機序列號 seq=m,此時客戶端狀態(tài)由 ESTABLISHED 變?yōu)?nbsp;FIN_WAIT_1;
3)第二次揮手,服務(wù)端收到含 FIN=1 標志位的數(shù)據(jù)包,就知道客戶端要斷開連接,服務(wù)端會向客戶端發(fā)送含 ACK=1 標志位的應(yīng)答數(shù)據(jù)包,確認序列號 ack=m+1,此時服務(wù)端狀態(tài)由 ESTABLISHED 變?yōu)?nbsp;CLOSE_WAIT;
4)客戶端收到含 ACK=1 標志位的應(yīng)答數(shù)據(jù)包,知道服務(wù)端的可以斷開的意思,此時客戶端狀態(tài)由 FIN_WAIT_1 變?yōu)?nbsp;FIN_WAIT_2;(第一、二次揮手也只是雙方交換一下意見而已)
5)第三次揮手,服務(wù)端處理完剩下的數(shù)據(jù)后再次向客戶端發(fā)送含 FIN=1 標志位的數(shù)據(jù)包,隨機序列號 seq=n,告訴客戶端現(xiàn)在可以真正的斷開連接了,此時服務(wù)端狀態(tài)由 CLOSE_WAIT 變?yōu)?nbsp;LAST_ACK;
6)第四次揮手,客戶端收到服務(wù)端再次發(fā)送的含 FIN=1 標志位的數(shù)據(jù)包,就知道服務(wù)端處理好了可以斷開連接了,但是客戶端為了慎重起見,不會立馬關(guān)閉連接,而是改狀態(tài),且向服務(wù)端發(fā)送含 ACK=1 標志位的應(yīng)答數(shù)據(jù)包,確認序列號 ack=n+1,此時客戶端狀態(tài)由 FIN_WAIT_2 變?yōu)?nbsp;TIME_WAIT;
等待 2 個MSL時間還是未收到服務(wù)端發(fā)過來的數(shù)據(jù),則表明服務(wù)端已經(jīng)關(guān)閉連接了,客戶端也會關(guān)閉連接釋放資源,此時客戶端狀態(tài)由 TIME_WAIT 變?yōu)?nbsp;CLOSED;
也就是說 TIME_WAIT 狀態(tài)存在時長在 1~4分鐘;
7)服務(wù)端收到含 ACK=1 標志位的應(yīng)答數(shù)據(jù)包,知道客戶端確認可以斷開了,就立即關(guān)閉連接釋放資源,此時服務(wù)端狀態(tài)由 LAST_ACK 變?yōu)?nbsp;CLOSED;
SYN 洪水攻擊(SYN Flood)
是一種 DoS攻擊(拒絕服務(wù)攻擊),大概原理是偽造大量的TCP請求,服務(wù)端收到大量的第一次握手的數(shù)據(jù)包,且都會發(fā)第二次握手數(shù)據(jù)包去回應(yīng),但是因為 IP 是偽造的,一直都不會有第三次握手數(shù)據(jù)包,導(dǎo)致服務(wù)端存在大量的半連接,即 SYN_RCVD 狀態(tài)的連接,導(dǎo)致半連接隊列被塞滿,且服務(wù)端默認會發(fā) 5 個第二次握手數(shù)據(jù)包,耗費大量 CPU 和內(nèi)存資源,使得正常的連接請求進不來;