三次握手钞楼,建立連接
- 第一次握手:建立連接時(shí),客戶端A發(fā)送SYN包(SYN=j)到服務(wù)器B袄琳,并進(jìn)入SYN_SEND狀態(tài)询件,等待服務(wù)器B確認(rèn)。
- 第二次握手:服務(wù)器B收到SYN包唆樊,確認(rèn)客戶A的SYN(ACK=j+1)宛琅,同時(shí)自己也發(fā)送一個(gè)SYN包(SYN=k),即SYN+ACK包逗旁,此時(shí)服務(wù)器B進(jìn)入SYN_RECV狀態(tài)嘿辟。
- 第三次握手:客戶端A收到服務(wù)器B的SYN+ACK包,向服務(wù)器B發(fā)送確認(rèn)包ACK(ACK=k+1)片效,此包發(fā)送完畢红伦,客戶端A和服務(wù)器B進(jìn)入ESTABLISHED狀態(tài),完成三次握手淀衣。
完成三次握手昙读,客戶端與服務(wù)器開始傳送數(shù)據(jù)。(事實(shí)上膨桥,第三次握手的IP包中蛮浑,就已經(jīng)可以攜帶數(shù)據(jù))
四次揮手,拆除連接
由于TCP連接是全雙工的国撵,一個(gè)TCP連接存在雙向的讀寫通道陵吸。 因此每個(gè)方向都必須單獨(dú)進(jìn)行關(guān)閉。當(dāng)一方完成它的數(shù)據(jù)發(fā)送任務(wù)后就能發(fā)送一個(gè)FIN包來終止這個(gè)方向的連接介牙。收到一個(gè)FIN包只意味著這一方向上沒有數(shù)據(jù)流動(dòng),一個(gè)TCP連接在收到一個(gè)FIN包后仍可以在另一個(gè)方向上收發(fā)數(shù)據(jù)澳厢。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動(dòng)關(guān)閉环础,而另一方執(zhí)行被動(dòng)關(guān)閉囚似。
TCP連接的拆除需要發(fā)送四個(gè)包,因此稱為四次揮手(four-way handshake)线得∪幕剑客戶端或服務(wù)器均可主動(dòng)發(fā)起揮手動(dòng)作,在socket編程中贯钩,任何一方執(zhí)行close()操作即可產(chǎn)生揮手操作募狂。
- 客戶端A發(fā)送一個(gè)FIN,用來關(guān)閉客戶A到服務(wù)器B的數(shù)據(jù)傳送角雷。 (服務(wù)器讀通道關(guān)閉)
- 服務(wù)器B收到這個(gè)FIN祸穷,它發(fā)回一個(gè)ACK,確認(rèn)序號(hào)為收到的序號(hào)加1勺三。和SYN一樣雷滚,一個(gè)FIN將占用一個(gè)序號(hào)。 (客戶端寫通道關(guān)閉)
- 服務(wù)器B關(guān)閉與客戶端A的連接吗坚,發(fā)送一個(gè)FIN給客戶端A祈远。 (服務(wù)器寫通道關(guān)閉)
- 客戶端A發(fā)回ACK報(bào)文確認(rèn),并將確認(rèn)序號(hào)設(shè)置為收到序號(hào)加1商源。 (客戶端讀通道關(guān)閉)
FIN包的主動(dòng)發(fā)起方關(guān)閉自己的寫通道车份,被動(dòng)方關(guān)閉自己的讀通道。
從建立連接到斷開連接TCP的狀態(tài)遷移
客戶端TCP狀態(tài)遷移:
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
服務(wù)器TCP狀態(tài)遷移:
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
各個(gè)狀態(tài)意義如下:
LISTEN - 偵聽來自遠(yuǎn)方TCP端口的連接請求牡彻;
SYN-SENT -在發(fā)送連接請求后等待匹配的連接請求扫沼;
SYN-RECEIVED - 在收到和發(fā)送一個(gè)連接請求后等待對連接請求的確認(rèn);
ESTABLISHED- 代表一個(gè)打開的連接讨便,數(shù)據(jù)可以傳送給用戶充甚;
FIN-WAIT-1 - 等待遠(yuǎn)程TCP的連接中斷請求,或先前的連接中斷請求的確認(rèn)霸褒;
FIN-WAIT-2 - 從遠(yuǎn)程TCP等待連接中斷請求伴找;
CLOSE-WAIT - 等待從本地用戶發(fā)來的連接中斷請求;
CLOSING -等待遠(yuǎn)程TCP對連接中斷的確認(rèn)废菱;
LAST-ACK - 等待原來發(fā)向遠(yuǎn)程TCP的連接中斷請求的確認(rèn)技矮;
TIME-WAIT -等待足夠的時(shí)間以確保遠(yuǎn)程TCP接收到連接中斷請求的確認(rèn);
CLOSED - 沒有任何連接狀態(tài)殊轴;
TCP的TIME_WAIT和Close_Wait狀態(tài)
SYN_RECV
服務(wù)端收到建立連接的SYN之后&&沒有收到SYN的ACK包之前的時(shí)候處在SYN_RECV狀態(tài)衰倦。有兩個(gè)相關(guān)系統(tǒng)配置:
- net.ipv4.tcp_synack_retries :INTEGER (默認(rèn)值是5)
對于遠(yuǎn)端的連接請求SYN,內(nèi)核會(huì)發(fā)送SYN + ACK數(shù)據(jù)報(bào)旁理,以確認(rèn)收到上一個(gè) SYN連接請求包樊零。這是所謂的三次握手( threeway handshake)機(jī)制的第二個(gè)步驟。這里決定內(nèi)核在放棄連接之前所送出的 SYN+ACK 數(shù)目。不應(yīng)該大于255驻襟,默認(rèn)值是5夺艰,對應(yīng)于180秒左右時(shí)間。通常我們不對這個(gè)值進(jìn)行修改沉衣,因?yàn)槲覀兿M鸗CP連接不要因?yàn)榕紶柕膩G包而無法建立郁副。
- net.ipv4.tcp_syncookies
一般服務(wù)器都會(huì)設(shè)置net.ipv4.tcp_syncookies=1來防止SYN Flood攻擊滋尉。假設(shè)一個(gè)用戶向服務(wù)器發(fā)送了SYN報(bào)文后突然死機(jī)或掉線狡孔,那么服務(wù)器在發(fā)出SYN+ACK應(yīng)答報(bào)文后是無法收到客戶端的ACK報(bào)文的(第三次握手無法完成)悠反,這種情況下服務(wù)器端一般會(huì)重試(再次發(fā)送SYN+ACK給客戶端)并等待一段時(shí)間后丟棄這個(gè)未完成的連接屿笼,這段時(shí)間的長度我們稱為SYN Timeout牡拇,一般來說這個(gè)時(shí)間是分鐘的數(shù)量級(大約為30秒-2分鐘)冈敛。
這些處在SYNC_RECV的TCP連接稱為半連接潦嘶,并存儲(chǔ)在內(nèi)核的半連接隊(duì)列中贰锁,在內(nèi)核收到對端發(fā)送的ACK包時(shí)會(huì)查找半連接隊(duì)列巷屿,并將符合的requst_sock信息存儲(chǔ)到完成三次握手的連接的隊(duì)列中固以,然后刪除此半連接。大量SYNC_RECV的TCP半連接會(huì)導(dǎo)致半連接隊(duì)列溢出嘱巾,這樣后續(xù)的連接建立請求會(huì)被內(nèi)核直接丟棄憨琳,這就是SYN Flood攻擊。
能夠有效防范SYN Flood攻擊的手段之一旬昭,就是SYN Cookie篙螟。SYN Cookie原理由D. J. Bernstain和 Eric Schenk發(fā)明。SYN Cookie是對TCP服務(wù)器端的三次握手協(xié)議作一些修改问拘,專門用來防范SYN Flood攻擊的一種手段遍略。它的原理是,在TCP服務(wù)器收到TCP SYN包并返回TCP SYN+ACK包時(shí)骤坐,不分配一個(gè)專門的數(shù)據(jù)區(qū)绪杏,而是根據(jù)這個(gè)SYN包計(jì)算出一個(gè)cookie值。在收到TCP ACK包時(shí)纽绍,TCP服務(wù)器在根據(jù)那個(gè)cookie值檢查這個(gè)TCP ACK包的合法性蕾久。如果合法,再分配專門的數(shù)據(jù)區(qū)進(jìn)行處理未來的TCP連接拌夏。
CLOSE_WAIT
發(fā)起TCP連接關(guān)閉的一方稱為client僧著,被動(dòng)關(guān)閉的一方稱為server。被動(dòng)關(guān)閉的server收到FIN后障簿,但未發(fā)出ACK的TCP狀態(tài)是CLOSE_WAIT盹愚。出現(xiàn)這種狀況一般都是由于server端代碼的問題,如果你的服務(wù)器上出現(xiàn)大量CLOSE_WAIT站故,應(yīng)該要考慮檢查代碼皆怕。
TIME_WAIT
根據(jù)TCP協(xié)議定義的3次握手?jǐn)嚅_連接規(guī)定,發(fā)起socket主動(dòng)關(guān)閉的一方 socket將進(jìn)入TIME_WAIT狀態(tài)。TIME_WAIT狀態(tài)將持續(xù)2個(gè)MSL(Max Segment Lifetime),在Windows下默認(rèn)為4分鐘端逼,即240秒朗兵。TIME_WAIT狀態(tài)下的socket不能被回收使用. 具體現(xiàn)象是對于一個(gè)處理大量短連接的服務(wù)器污淋,如果是由服務(wù)器主動(dòng)關(guān)閉客戶端的連接顶滩,將導(dǎo)致服務(wù)器端存在大量的處于TIME_WAIT狀態(tài)的socket, 甚至比處于Established狀態(tài)下的socket多的多,嚴(yán)重影響服務(wù)器的處理能力寸爆,甚至耗盡可用的socket礁鲁,停止服務(wù)。
為什么需要TIME_WAIT赁豆?TIME_WAIT是TCP協(xié)議用以保證被重新分配的socket不會(huì)受到之前殘留的延遲重發(fā)報(bào)文影響的機(jī)制,是必要的邏輯保證仅醇。
和TIME_WAIT狀態(tài)有關(guān)的系統(tǒng)參數(shù)有一般有3個(gè):
- net.ipv4.tcp_fin_timeout,默認(rèn)60s魔种,減小fin_timeout析二,減少TIME_WAIT連接數(shù)量。
- net.ipv4.tcp_tw_reuse = 1表示開啟重用节预。允許將TIME-WAIT sockets重新用于新的TCP連接叶摄,默認(rèn)為0,表示關(guān)閉安拟;
- net.ipv4.tcp_tw_recycle = 1表示開啟TCP連接中TIME-WAIT sockets的快速回收蛤吓,默認(rèn)為0,表示關(guān)閉糠赦。
從上面可以看到会傲,主動(dòng)發(fā)起關(guān)閉連接的操作的一方將達(dá)到TIME_WAIT狀態(tài),而且這個(gè)狀態(tài)要保持Maximum Segment Lifetime的兩倍時(shí)間拙泽。為什么要這樣做而不是直接進(jìn)入CLOSED狀態(tài)淌山?
原因有二:
一、保證TCP協(xié)議的全雙工連接能夠可靠關(guān)閉
二顾瞻、保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失
先說第一點(diǎn)泼疑,如果Client直接CLOSED了,那么由于IP協(xié)議的不可靠性或者是其它網(wǎng)絡(luò)原因朋其,導(dǎo)致Server沒有收到Client最后回復(fù)的ACK王浴。那么Server就會(huì)在超時(shí)之后繼續(xù)發(fā)送FIN,此時(shí)由于Client已經(jīng)CLOSED了梅猿,就找不到與重發(fā)的FIN對應(yīng)的連接氓辣,最后Server就會(huì)收到RST而不是ACK,Server就會(huì)以為是連接錯(cuò)誤把問題報(bào)告給高層袱蚓。這樣的情況雖然不會(huì)造成數(shù)據(jù)丟失钞啸,但是卻導(dǎo)致TCP協(xié)議不符合可靠連接的要求。所以,Client不是直接進(jìn)入CLOSED体斩,而是要保持TIME_WAIT梭稚,當(dāng)再次收到FIN的時(shí)候,能夠保證對方收到ACK絮吵,最后正確的關(guān)閉連接弧烤。
再說第二點(diǎn),如果Client直接CLOSED蹬敲,然后又再向Server發(fā)起一個(gè)新連接暇昂,我們不能保證這個(gè)新連接與剛關(guān)閉的連接的端口號(hào)是不同的。也就是說有可能新連接和老連接的端口號(hào)是相同的伴嗡。一般來說不會(huì)發(fā)生什么問題急波,但是還是有特殊情況出現(xiàn):假設(shè)新連接和已經(jīng)關(guān)閉的老連接端口號(hào)是一樣的,如果前一次連接的某些數(shù)據(jù)仍然滯留在網(wǎng)絡(luò)中瘪校,這些延遲數(shù)據(jù)在建立新連接之后才到達(dá)Server澄暮,由于新連接和老連接的端口號(hào)是一樣的,又因?yàn)門CP協(xié)議判斷不同連接的依據(jù)是socket pair阱扬,于是泣懊,TCP協(xié)議就認(rèn)為那個(gè)延遲的數(shù)據(jù)是屬于新連接的,這樣就和真正的新連接的數(shù)據(jù)包發(fā)生混淆了价认。所以TCP連接還要在TIME_WAIT狀態(tài)等待2倍MSL嗅定,這樣可以保證本次連接的所有數(shù)據(jù)都從網(wǎng)絡(luò)中消失。