最近一段時(shí)間,看了Linux內(nèi)核中的網(wǎng)絡(luò)部分源碼档桃。在看完之后枪孩,一個(gè)很基本又經(jīng)典的問題又浮現(xiàn)在我的腦海即“TCP協(xié)議為什么需要三次握手”,以前看過一些文章藻肄,但自己覺得都不是很清晰蔑舞。下午有了點(diǎn)自己的想法,記錄一下嘹屯。
我們知道攻询,TCP協(xié)議是一個(gè)面向連接的,可靠州弟,全雙工的傳輸協(xié)議钧栖。其中全雙工的意思是說低零,通信雙方可以同時(shí)發(fā)送,接收數(shù)據(jù)拯杠,類似于打電話掏婶。那么為了能確保這樣的連接可以成功建立,至少需要保證通信雙方至少可以可靠地發(fā)送潭陪,接受一次數(shù)據(jù)雄妥。為了方便敘述,假設(shè)參與通信的雙方稱為A,B依溯。則在建立連接時(shí)老厌,需要讓A和B都認(rèn)為自己和對(duì)方都可以發(fā)送,接收數(shù)據(jù)黎炉。在連接還沒開始建立時(shí)枝秤,雙方均認(rèn)為自己無法發(fā)送和接收數(shù)據(jù)。方便表述拜隧,列表如下(左上角的字母表示站在誰的視角)
假設(shè)A發(fā)起TCP連接宿百,向B發(fā)送SYN包。如下圖所示洪添。
在B還未收到該SYN包之前垦页,A和B的對(duì)自身能力的認(rèn)知的變化是,A可以認(rèn)識(shí)到自己是有發(fā)送數(shù)據(jù)包的能力的干奢,至于自己能否接收數(shù)據(jù)包痊焊,B能否接收,能否發(fā)送數(shù)據(jù)包忿峻,都是未知的薄啥,就認(rèn)為沒有此能力。如下圖
在B接收到SYN包后,B就可以認(rèn)為自己有接收數(shù)據(jù)包的能力绰寞,也可以知道對(duì)端A有發(fā)送數(shù)據(jù)包的能力(因?yàn)榻邮盏搅薙YN包)到逊。A的認(rèn)知還未變化,如下圖所示滤钱。
B收到SYN包后铜靶,按照協(xié)議,會(huì)發(fā)送SYN+ACK包他炊。如下圖所示争剿。
在這之后已艰,在A接收到該包之前。B就可以認(rèn)為自己有發(fā)送包的能力秒梅。此時(shí)旗芬,A,B的認(rèn)知變?yōu)椋?/p>
在A收到SYN+ACK包后疮丛,A就可以認(rèn)為自己有接收數(shù)據(jù)包的能力,并且B成功收到了自己的SYN數(shù)據(jù)包辆它,B也有了接收數(shù)據(jù)的能力誊薄。同時(shí)這個(gè)SYN+ACK是B發(fā)來的,也就知道了B有發(fā)送數(shù)據(jù)的能力锰茉。此時(shí)呢蔫,A,B的認(rèn)知變成:
在此時(shí),看到A端已經(jīng)可以認(rèn)為自己协屡,對(duì)端B都具有了發(fā)送俏脊,接收的能力。但這是B還無法確認(rèn)A有正常接收自己數(shù)據(jù)包的能力肤晓。所以需要A再次發(fā)送一個(gè)ACK包爷贫,來讓B確認(rèn)自己可以正常接收數(shù)據(jù)包,“點(diǎn)亮”B的所有“認(rèn)知”补憾。從而正常地進(jìn)行全雙工通信漫萄,如下圖:
在B成功接收A發(fā)來的ACK包后,A,B就都可以認(rèn)為自己盈匾,對(duì)端都有發(fā)送和接收數(shù)據(jù)的能力腾务。如下圖
從以上流程可以看到削饵,3次握手岩瘦,是可以讓通信雙發(fā)達(dá)成自己,對(duì)方都可以進(jìn)行正常全雙工通信認(rèn)知的最少“捂手”次數(shù)葵孤。所以TCP選擇了3次握手~