1 三次握手
TCP是面向連接的束凑,無論哪一方向另一方發(fā)送數(shù)據(jù)之前晒旅,都必須在雙方之間建立一個(gè)連接。
在TCP/IP協(xié)議中汪诉,TCP協(xié)議提供可靠的連接服務(wù)废恋,連接是通過三次握手進(jìn)行初始化的。三次握手的目的是同步連接雙方的序列號(hào)和確認(rèn)號(hào)扒寄,并交換TCP窗口大小信息鱼鼓。
名詞解釋:
SYN:synchronous 同步。SYN是6個(gè)控制位中的一個(gè)该编,值為1時(shí)表示當(dāng)前報(bào)文段的作用是同步序號(hào)迄本。
seq:Sequence Number 序號(hào)。第一個(gè)字節(jié)的編號(hào)课竣,在“TCP報(bào)文結(jié)構(gòu)“中有介紹嘉赎。
ACK:Acknowledgement 確認(rèn)字符。ACK是6個(gè)控制位中的一個(gè)于樟,值為1時(shí)表示前一個(gè)報(bào)文段已確認(rèn)收到公条。
ack:小寫的ack表示確認(rèn)號(hào)。即接收方期望接收的下一個(gè)字節(jié)的編號(hào)迂曲。
第一次握手:
客戶端發(fā)送SYN報(bào)文段靶橱,將SYN位置為1,seq為X(X為一個(gè)隨機(jī)數(shù))路捧;然后客戶端進(jìn)入SYN_SEND狀態(tài)关霸,等待服務(wù)器的確認(rèn)。
注意:這個(gè)報(bào)文段中不包括確認(rèn)號(hào)杰扫,也沒有定義窗口大小队寇。SYN報(bào)文段是一個(gè)控制報(bào)文段,它不攜帶任何數(shù)據(jù)章姓。但是它消耗了一個(gè)序號(hào)佳遣,當(dāng)數(shù)據(jù)傳送開始時(shí)炭序,序號(hào)就應(yīng)當(dāng)加1。
第二次握手:
服務(wù)器發(fā)送SYN+ACK報(bào)文段苍日,其中SYN和ACK這兩個(gè)控制位都置為1惭聂。
這個(gè)報(bào)文段有兩個(gè)目的:
服務(wù)器使用這個(gè)報(bào)文段來同步它的初始序號(hào)(seq),以便從服務(wù)器向客戶端發(fā)送字節(jié)相恃。
服務(wù)器通過ACK標(biāo)志告訴客戶端已經(jīng)收到來自客戶端的SYN報(bào)文段辜纲。同時(shí)設(shè)置ack表示希望從客戶端收到的下一個(gè)字節(jié)編號(hào),也因?yàn)樵O(shè)置了ack拦耐,服務(wù)器還定義了接收窗口的大小(rwnd)耕腾。
此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)。
注意:SYN+ACK報(bào)文段不攜帶任何數(shù)據(jù)杀糯,但要消耗一個(gè)序號(hào)扫俺。
第三次握手:
客戶端發(fā)送ACK報(bào)文段。
ACK標(biāo)志和確認(rèn)號(hào)(ack)用于告訴服務(wù)器已經(jīng)收到來自服務(wù)器的SYN+ACK報(bào)文段固翰。
序號(hào)(seq)和第一次握手的SYN報(bào)文段的序號(hào)一樣狼纬,也就是說這個(gè)ACK報(bào)文段不消耗任何序號(hào)。但在某些實(shí)現(xiàn)中骂际,連接階段的第三個(gè)報(bào)文段(ACK報(bào)文段)可以攜帶客戶端的第一個(gè)數(shù)據(jù)塊疗琉,此時(shí),第三個(gè)報(bào)文段必須有一個(gè)新的序號(hào)來表示數(shù)據(jù)中的第一個(gè)字節(jié)編號(hào)歉铝。結(jié)論就是:ACK報(bào)文段如果不攜帶數(shù)據(jù)就不消耗序號(hào)盈简。
此時(shí)客戶端和服務(wù)器都進(jìn)入了ESTABLISHED狀態(tài),完成TCP三次握手太示。(單詞解釋:establish:建立)
為什么要三次握手柠贤?
為了防止已經(jīng)失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)器,因而產(chǎn)生錯(cuò)誤类缤。
具體例子:
client發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒有丟失臼勉,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間的滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server呀非。本來這是一個(gè)早已失效的報(bào)文段坚俗。但server收到此失效的連接請(qǐng)求報(bào)文段后镜盯,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請(qǐng)求岸裙。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接速缆。假設(shè)不采用“三次握手”降允,那么只要server發(fā)出確認(rèn),新的連接就建立了艺糜。由于現(xiàn)在client并沒有發(fā)出建立連接的請(qǐng)求剧董,因此不會(huì)理睬server的確認(rèn)幢尚,也不會(huì)向server發(fā)送數(shù)據(jù)。但server卻以為新的運(yùn)輸連接已經(jīng)建立翅楼,并一直等待client發(fā)來數(shù)據(jù)尉剩。這樣,server的很多資源就白白浪費(fèi)掉了毅臊。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生理茎。
2 四次揮手
客戶端和服務(wù)器通過三次握手建立了TCP連接,當(dāng)數(shù)據(jù)傳送完畢管嬉,需要斷開連接皂林,對(duì)于TCP的斷開連接,有“四次揮手過程”蚯撩。
第一次揮手:
主動(dòng)方(可以是客戶端或者服務(wù)器)础倍,設(shè)置seq=x,向被動(dòng)方發(fā)送一個(gè)FIN報(bào)文段(FIN報(bào)文段可以包含要發(fā)送的最后一塊數(shù)據(jù))胎挎;此時(shí)沟启,主動(dòng)方進(jìn)入FIN_WAIT_1狀態(tài);這表示主動(dòng)方已經(jīng)沒有數(shù)據(jù)要發(fā)送給被動(dòng)方了犹菇。
第二次揮手:
被動(dòng)方收到了主動(dòng)方的FIN報(bào)文段美浦,向主動(dòng)方回了一個(gè)ACK報(bào)文段,ack=x+1项栏;此時(shí)主動(dòng)方進(jìn)入FIN_WAIT_2狀態(tài)浦辨;這表示被動(dòng)方告訴主動(dòng)方,我“同意”你的關(guān)閉請(qǐng)求沼沈。
第三次揮手:
被動(dòng)方向主動(dòng)方發(fā)送FIN報(bào)文段流酬,請(qǐng)求關(guān)閉連接;此時(shí)被動(dòng)方進(jìn)入LAST_ACK狀態(tài)列另。
第四次揮手:
主動(dòng)方收到被動(dòng)方的FIN報(bào)文段芽腾,向被動(dòng)方發(fā)送ACK報(bào)文段,然后主動(dòng)方進(jìn)入TIME_WAIT狀態(tài)页衙;被動(dòng)方收到主動(dòng)方的ACK報(bào)文段后摊滔,就關(guān)閉連接;此時(shí)主動(dòng)方等待2MSL(MSL:Maximum Segment Lifetime店乐,報(bào)文段最大生存時(shí)間)后依然沒有收到回復(fù)艰躺,則證明被動(dòng)方已正常關(guān)閉,那么主動(dòng)方也可以關(guān)閉了眨八。
為什么要四次揮手腺兴?
TCP協(xié)議是一種面向連接的、可靠的廉侧、基于字節(jié)流的運(yùn)輸層通信協(xié)議页响。TCP是全雙工模式篓足,這就意味著,當(dāng)主機(jī)1發(fā)出FIN報(bào)文段時(shí)闰蚕,只是表示主機(jī)1已經(jīng)沒有數(shù)據(jù)要發(fā)送了栈拖,主機(jī)1告訴主機(jī)2,它的數(shù)據(jù)已經(jīng)全部發(fā)送完畢了没陡;但是辱魁,這個(gè)時(shí)候主機(jī)1還是可以接受來自主機(jī)2的數(shù)據(jù);當(dāng)主機(jī)2返回ACK報(bào)文段時(shí)诗鸭,表示它已經(jīng)知道主機(jī)1沒有數(shù)據(jù)發(fā)送了染簇,但是主機(jī)2還是可以發(fā)送數(shù)據(jù)到主機(jī)1的;當(dāng)主機(jī)2也發(fā)送了FIN報(bào)文段時(shí)强岸,這個(gè)時(shí)候就表示主機(jī)2也沒有數(shù)據(jù)要發(fā)送了锻弓,就會(huì)告訴主機(jī)1规揪,我也沒有數(shù)據(jù)要發(fā)送了竿滨,之后彼此就會(huì)愉快的中斷這次TCP連接。
為什么要等待2MSL辽旋?
原因有二:
保證TCP協(xié)議的全雙工連接能夠可靠的關(guān)閉
保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失
第一點(diǎn):如果主機(jī)1直接CLOSED了妓盲,那么由于IP協(xié)議的不可靠性或者是其它網(wǎng)絡(luò)原因杂拨,導(dǎo)致主機(jī)2沒有收到主機(jī)1最后回復(fù)的ACK。那么主機(jī)2就會(huì)在超時(shí)之后繼續(xù)發(fā)送FIN悯衬,此時(shí)由于主機(jī)1已經(jīng)CLOSED了弹沽,就找不到與重發(fā)的FIN對(duì)應(yīng)的連接。所以筋粗,主機(jī)1不是直接進(jìn)入CLOSED策橘,而是要保持TIME_WAIT狀態(tài)。當(dāng)再次收到FIN的時(shí)候娜亿,能夠保證對(duì)方收到ACK丽已,最后正確的關(guān)閉連接。
第二點(diǎn):如果主機(jī)1直接CLOSED买决,然后又再向主機(jī)2發(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ò)中(稱為L(zhǎng)ost Duplicate)够挂,這些延遲數(shù)據(jù)在建立新連接之后才到達(dá)主機(jī)2旁仿,由于新連接和老連接的端口號(hào)是一樣的藕夫,TCP協(xié)議就認(rèn)為那個(gè)延遲的數(shù)據(jù)是屬于新連接的孽糖,這樣就和真正的新連接的數(shù)據(jù)包發(fā)生混淆了枯冈。所以TCP連接要在TIME_WAIT狀態(tài)等待2倍MSL,保證本次連接的所有數(shù)據(jù)都從網(wǎng)絡(luò)中消失办悟。
以上內(nèi)容摘自:
https://github.com/LRH1993/android_interview/blob/master/computer-networks/tcpip.md
《TCP/IP協(xié)議族》第四版