TCP協(xié)議提供可靠的連接服務(wù)锁蠕,采用3次握手建立一個(gè)鏈接夷野。
第一次握手:
建立連接時(shí),客戶端發(fā)送SYN包(SYN=j)到服務(wù)器荣倾,并進(jìn)入SYN_SEND狀態(tài)悯搔,等待服務(wù)器確認(rèn)。
(SYN:同步序列編號(hào)(Synchronize Sequence Numbers)舌仍。)
第二次握手:
服務(wù)器收到SYN包妒貌,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k)铸豁,即SYN+ACK包灌曙,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)。
第三次握手:
客戶端收到服務(wù)器的SYN+ACK包推姻,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1)平匈,此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài)藏古,完成3次握手增炭。
完成3次握手,客戶端與服務(wù)器端開始傳送數(shù)據(jù)拧晕。
涉及的幾個(gè)重要概念:
1.未連接隊(duì)列
在3次握手協(xié)議中隙姿,服務(wù)器維護(hù)一個(gè)未連接隊(duì)列,該隊(duì)列為每個(gè)客戶端的SYN包(syn=j)開設(shè)一個(gè)條目厂捞,該條目表明服務(wù)器已收到SYN包输玷,并向客戶發(fā)出確認(rèn)队丝,正在等待客戶的確認(rèn)包。這些條目所標(biāo)識(shí)的連接在服務(wù)器處于SYN_RECV狀態(tài)欲鹏,當(dāng)服務(wù)器收到客戶的確認(rèn)包時(shí)机久,刪除該條目,服務(wù)器進(jìn)入ESTABLISHED狀態(tài)赔嚎。
2. backlog參數(shù)
未連接隊(duì)列的最大容納數(shù)
3.SYN-ACK重傳次數(shù)
服務(wù)器發(fā)送完SYN-ACK包膘盖,如果未收到客戶端確認(rèn)包,服務(wù)器進(jìn)入首次重傳尤误,等待一段時(shí)間仍未收到客戶確認(rèn)包侠畔,進(jìn)行第二次重傳,如果重傳次數(shù)超過系統(tǒng)規(guī)定的最大重傳次數(shù)损晤,系統(tǒng)將該連接信息從半連接隊(duì)列中刪除软棺。注意,每次重傳等待的時(shí)間不一定相同尤勋。
4. 半連接存活時(shí)間/ timeout時(shí)間/ SYN_RECV存活時(shí)間
半連接隊(duì)列的條目存活的最長(zhǎng)時(shí)間喘落,即服務(wù)從收到SYN包到確認(rèn)這個(gè)報(bào)文無效的最長(zhǎng)時(shí)間,該時(shí)間值是所有重傳請(qǐng)求包的最長(zhǎng)等待時(shí)間綜合斥黑。
為什么不是兩次
我們先來將三次握手這個(gè)過程捋一遍揖盘。(S-服務(wù)端,C-客戶端)
第一次握手后锌奴,S可以確認(rèn)自己收?qǐng)?bào)文與C發(fā)報(bào)文的功能都正常兽狭,而C呢,它什么都不能確認(rèn)鹿蜀。
第二次握手后箕慧,C可以確認(rèn)自己的收發(fā)報(bào)文與S的收發(fā)報(bào)文功能都正常,也就是認(rèn)為連接已建立茴恰。
那么第三次呢颠焦,S也可以確認(rèn)雙方能夠正常通信。
假想一下往枣,如果我們?nèi)サ袅说谌文兀?/p>
因?yàn)槲覀儾贿M(jìn)行第三次握手伐庭,所以在S對(duì)C的請(qǐng)求進(jìn)行回應(yīng)(第二次握手)后,就會(huì)理所當(dāng)然的認(rèn)為連接已建立分冈,而如果C并沒有收到S的回應(yīng)呢圾另?此時(shí),C仍認(rèn)為連接未建立雕沉,S會(huì)對(duì)已建立的連接保存必要的資源集乔,如果大量的這種情況,S會(huì)崩潰坡椒。
因此第三次握手是必要的扰路。
首先尤溜,如果樂于思考的同學(xué)應(yīng)該會(huì)對(duì)上面有這樣的疑問:
既然沒法確認(rèn)第二次的握手,C是否可以收到汗唱,
那么怎么確定第三次握手S就可以收到呢宫莱?
不錯(cuò),這根本沒法確定哩罪,因?yàn)橥耆煽康耐ㄐ艆f(xié)議是根本不存在的梢睛,我們?nèi)魏蔚耐ㄐ艆f(xié)議都是在接受這樣的現(xiàn)實(shí)情況之上進(jìn)行的。
而三次握手后识椰,C和S至少可以確認(rèn)之前的通信情況,但無法確認(rèn)之后的情況深碱。
在這個(gè)道理上說腹鹉,無論是四次還是五次或是更多次都是徒勞的。
四次揮手
假設(shè)Client端發(fā)起中斷連接請(qǐng)求敷硅,也就是發(fā)送FIN報(bào)文功咒。Server端接到FIN報(bào)文后,意思是說"我Client端沒有數(shù)據(jù)要發(fā)給你了"绞蹦,但是如果你還有數(shù)據(jù)沒有發(fā)送完成力奋,則不必急著關(guān)閉Socket,可以繼續(xù)發(fā)送數(shù)據(jù)幽七。所以你先發(fā)送ACK景殷,"告訴Client端,你的請(qǐng)求我收到了澡屡,但是我還沒準(zhǔn)備好猿挚,請(qǐng)繼續(xù)你等我的消息"。這個(gè)時(shí)候Client端就進(jìn)入FIN_WAIT狀態(tài)驶鹉,繼續(xù)等待Server端的FIN報(bào)文绩蜻。當(dāng)Server端確定數(shù)據(jù)已發(fā)送完成,則向Client端發(fā)送FIN報(bào)文室埋,"告訴Client端办绝,好了,我這邊數(shù)據(jù)發(fā)完了姚淆,準(zhǔn)備好關(guān)閉連接了"孕蝉。Client端收到FIN報(bào)文后,"就知道可以關(guān)閉連接了肉盹,但是他還是不相信網(wǎng)絡(luò)昔驱,怕Server端不知道要關(guān)閉,所以發(fā)送ACK后進(jìn)入TIME_WAIT狀態(tài)上忍,如果Server端沒有收到ACK則可以重傳骤肛∧杀荆“,Server端收到ACK后腋颠,"就知道可以斷開連接了"繁成。Client端等待了2MSL(最大報(bào)文段生存時(shí)間)后依然沒有收到回復(fù),則證明Server端已正常關(guān)閉淑玫,那好巾腕,我Client端也可以關(guān)閉連接了。Ok絮蒿,TCP連接就這樣關(guān)閉了尊搬!
為什么必須是四次揮手?不能是兩次土涝?
TCP連接是全雙工的,也就是說接收到FIN只是說沒有數(shù)據(jù)再發(fā)過來但是還是可以發(fā)送數(shù)據(jù)的但壮,也就是接受到一個(gè)FIN只是關(guān)閉了一個(gè)方向的數(shù)據(jù)傳輸冀泻,另一個(gè)方向還可以繼續(xù)發(fā)送數(shù)據(jù)。在四次揮手的時(shí)候也是這樣前兩次揮手只是確認(rèn)關(guān)閉了一個(gè)方向的數(shù)據(jù)蜡饵,加上后面兩次揮手才真正的關(guān)閉了整個(gè)全雙工連接弹渔。
【問題1】為什么連接的時(shí)候是三次握手食听,關(guān)閉的時(shí)候卻是四次握手供置?
答:因?yàn)楫?dāng)Server端收到Client端的SYN連接請(qǐng)求報(bào)文后,可以直接發(fā)送SYN+ACK報(bào)文肩袍。其中ACK報(bào)文是用來應(yīng)答的您没,SYN報(bào)文是用來同步的鸟召。但是關(guān)閉連接時(shí),當(dāng)Server端收到FIN報(bào)文時(shí)氨鹏,很可能并不會(huì)立即關(guān)閉SOCKET欧募,所以只能先回復(fù)一個(gè)ACK報(bào)文,告訴Client端仆抵,"你發(fā)的FIN報(bào)文我收到了"跟继。只有等到我Server端所有的報(bào)文都發(fā)送完了,我才能發(fā)送FIN報(bào)文镣丑,因此不能一起發(fā)送舔糖。故需要四步握手。
【問題2】為什么TIME_WAIT狀態(tài)需要經(jīng)過2MSL(最大報(bào)文段生存時(shí)間)才能返回到CLOSE狀態(tài)莺匠?
答:雖然按道理金吗,四個(gè)報(bào)文都發(fā)送完畢,我們可以直接進(jìn)入CLOSE狀態(tài)了,但是我們必須假設(shè)網(wǎng)絡(luò)是不可靠的摇庙,有可以最后一個(gè)ACK丟失旱物。所以TIME_WAIT狀態(tài)就是用來重發(fā)可能丟失的ACK報(bào)文。