提到TCP和UDP的區(qū)別杰妓,很容易想到的就是TCP的可靠性蓬痒,那TCP是通過(guò)什么機(jī)制實(shí)現(xiàn)了可靠性的呢?解釋這個(gè)之前先來(lái)區(qū)分TCP中的大寫(xiě)ACK和小寫(xiě)ack围肥。看一張經(jīng)典的TCP三次握手過(guò)程圖:
這張圖里似乎有個(gè)大寫(xiě)的ACK也有個(gè)小寫(xiě)的ack蜂怎,這也是容易混淆的地方穆刻。
大寫(xiě)的ACK是控制位,在TCP報(bào)文頭中有8個(gè)標(biāo)志比特派敷,也就是TCP報(bào)文頭中有8位大小的數(shù)據(jù)是標(biāo)志位蛹批,看一下TCP報(bào)文格式更好理解:
它們中的多個(gè)可以同時(shí)被設(shè)置成1:
CWR(Congestion Window Reduce):擁塞窗口減少標(biāo)志,用來(lái)表明它接收到了設(shè)置ECE標(biāo)志的TCP包篮愉。并且腐芍,發(fā)送方收到消息之后,通過(guò)減小發(fā)送窗口的大小來(lái)降低發(fā)送速率试躏。
ECE(ECN Echo):用來(lái)在TCP三次握手時(shí)表明一個(gè)TCP端是具備ECN功能的猪勇。在數(shù)據(jù)傳輸過(guò)程中,它也用來(lái)表明接收到的TCP包的IP頭部的ECN被設(shè)置為 11颠蕴,即網(wǎng)絡(luò)線路擁堵泣刹。
URG(Urgent):表示本報(bào)文段中發(fā)送的數(shù)據(jù)是否包含緊急數(shù)據(jù)。URG=1時(shí)表示有緊急數(shù)據(jù)犀被。當(dāng)URG=1時(shí)椅您,后面的緊急指針字段才有效。
ACK:表示前面的確認(rèn)號(hào)字段是否有效寡键。ACK=1時(shí)表示有效掀泳。只有當(dāng) ACK=1時(shí),前面的確認(rèn)號(hào)字段才有效。TCP規(guī)定,連接建立后讯柔,ACK必須為 1。
PSH(Push):告訴對(duì)方收到該報(bào)文段后是否立即把數(shù)據(jù)推送給上層马僻。如果值為1,表示應(yīng)當(dāng)立即把數(shù)據(jù)提交給上層注服,而不是緩存起來(lái)韭邓。
RST:表示是否重置連接措近。如果RST=1,說(shuō)明TCP連接出現(xiàn)了嚴(yán)重錯(cuò)誤(如主機(jī)崩潰)仍秤,必須釋放連接熄诡,然后再重新建立連接。
SYN:在建立連接時(shí)使用诗力,用來(lái)同步序號(hào)凰浮。當(dāng)SYN=1,ACK=0時(shí)苇本,表示這是一個(gè)請(qǐng)求建立連接的報(bào)文段袜茧;當(dāng)SYN=1,ACK=1時(shí)瓣窄,表示對(duì)方同意建立連接笛厦。SYN=1時(shí),說(shuō)明這是一個(gè)請(qǐng)求建立連接或同意建立連接的報(bào)文俺夕。只有在前兩次握手中SYN才為1裳凸。
FIN:標(biāo)記數(shù)據(jù)是否發(fā)送完畢。如果 FIN=1劝贸,表示數(shù)據(jù)已經(jīng)發(fā)送完成姨谷,可以釋放連接。
這是大寫(xiě)的ACK映九,而小寫(xiě)的ack是確認(rèn)序列號(hào)梦湘,和它一對(duì)的是seq即順序序列號(hào),也就是上圖TCP報(bào)文格式中的Sequence Number和Acknowledgment Number件甥。
前面說(shuō)了這么多只是為了區(qū)分TCP中的大寫(xiě)ACK和小寫(xiě)ack捌议,也沒(méi)其他方法就用大小寫(xiě)區(qū)分吧,本文關(guān)注的重點(diǎn)就是TCP中的seq和ack機(jī)制引有,通過(guò)它們實(shí)現(xiàn)了TCP的可靠性傳輸瓣颅,當(dāng)然TCP通過(guò)很多方面去保證了可靠性傳輸,這里seq和ack機(jī)制是防止數(shù)據(jù)丟失丟包的機(jī)制譬正。
順序號(hào)seq:用來(lái)標(biāo)識(shí)從TCP源端向TCP目的端發(fā)送的數(shù)據(jù)字節(jié)流弄捕,它表示在這個(gè)報(bào)文段中的第一個(gè)數(shù)據(jù)字節(jié)的順序號(hào)。理解起來(lái)就是TCP用順序號(hào)對(duì)每個(gè)字節(jié)進(jìn)行計(jì)數(shù)导帝。由上圖TCP報(bào)文格式中可以看出序號(hào)是 32bit 的無(wú)符號(hào)數(shù),序號(hào)到達(dá) 后又重新開(kāi)始計(jì)數(shù)穿铆。當(dāng)建立一個(gè)新的連接時(shí)您单,順序號(hào)字段包含由這個(gè)主機(jī)選擇的該連接的初始順序號(hào) ISN ( Initial Sequence Number ),也就是說(shuō)seq并不一定是從0開(kāi)始的荞雏,所以剛在畫(huà)TCP三次握手的時(shí)候虐秦,寫(xiě)的seq=x平酿,即使還沒(méi)有數(shù)據(jù)傳輸,seq包含了ISN后就成了一個(gè)隨機(jī)數(shù)悦陋,并不是0蜈彼。
確認(rèn)號(hào)ack:理解起來(lái)就一句話,所期望收到的下一個(gè)順序號(hào)seq俺驶。
TCP為應(yīng)用層提供全雙工服務(wù)幸逆,這意味數(shù)據(jù)能在兩個(gè)方向上獨(dú)立地進(jìn)行傳輸,也就是說(shuō)服務(wù)端和客戶(hù)端都可能成為數(shù)據(jù)接收或者數(shù)據(jù)發(fā)送的一端暮现。
數(shù)據(jù)發(fā)送端在發(fā)送TCP報(bào)文時(shí)还绘,計(jì)算在本次seq計(jì)數(shù)內(nèi),之前所有發(fā)送的報(bào)文中數(shù)據(jù)長(zhǎng)度之和是多少栖袋,也就是計(jì)數(shù)記到哪里了拍顷,這就是seq。然后再計(jì)算之前所有收到的報(bào)文中收到的數(shù)據(jù)長(zhǎng)度之和是多少塘幅,這就是ack昔案。需要注意的是seq和ack是分開(kāi)計(jì)數(shù)的。需要注意的是电媳,SYN和FIN的TCP報(bào)文傳輸雖然沒(méi)有數(shù)據(jù)踏揣,但是數(shù)據(jù)長(zhǎng)度算1,ACK的傳輸匆背,數(shù)據(jù)長(zhǎng)度算0呼伸。
數(shù)據(jù)接收端收到TCP報(bào)文后,將這次報(bào)文中的seq取出來(lái)钝尸,和自己最后一次發(fā)送的ack對(duì)比括享,如果一致,則代表數(shù)據(jù)沒(méi)有丟失珍促,理解起來(lái)就是這次的順序號(hào)和上次自己期望的順序號(hào)一致嘛铃辖。如果不一致就說(shuō)明有丟包發(fā)生。其實(shí)就是TCP用0~對(duì)每個(gè)字節(jié)進(jìn)行計(jì)數(shù)猪叙,用下圖舉個(gè)例子解釋一下:
三個(gè)過(guò)程:
1.A在發(fā)送某個(gè)TCP報(bào)文前娇斩,發(fā)現(xiàn)此時(shí)自己這邊的seq計(jì)數(shù)已經(jīng)到了x,那這次的報(bào)文中seq=x穴翩,也就是在一次seq計(jì)數(shù)內(nèi)犬第,該端之前所有發(fā)送的報(bào)文中數(shù)據(jù)長(zhǎng)度之和為x。然后這次又在這個(gè)報(bào)文中攜帶了長(zhǎng)度為100bit的數(shù)據(jù)芒帕。
2.B在收到這個(gè)報(bào)文后歉嗓,拿到報(bào)文中的seq=x,又拿到了長(zhǎng)度為100bit的數(shù)據(jù)背蟆,然后回包的時(shí)候ack=x+100鉴分。意思是告訴B你已經(jīng)發(fā)了x+100位的數(shù)據(jù)了哮幢,下次發(fā)包的時(shí)候別忘了把seq改成x+100。
3.A收到B回的數(shù)據(jù)包后志珍,拿到報(bào)文中的ack=x+100橙垢,然后和自己這邊的計(jì)數(shù)著的seq一比對(duì),如果一樣伦糯,說(shuō)明A發(fā)的B都收到了沒(méi)問(wèn)題柜某,如果不一樣,假如A一看自己這邊的seq已經(jīng)等于y了舔株,也就是自己計(jì)數(shù)著的已經(jīng)發(fā)送y位的數(shù)據(jù)了莺琳,可是聽(tīng)B的意思它才收到x+100位數(shù)據(jù),丟包了唄载慈。然后就是重發(fā)什么的是TCP的另外一些機(jī)制惭等。
TCP就是通過(guò)seq和ack機(jī)制去確認(rèn)傳輸過(guò)程中有沒(méi)有丟包現(xiàn)象,前面說(shuō)在一次計(jì)數(shù)范圍內(nèi)办铡,seq并不一定是從0開(kāi)始的辞做,可以當(dāng)我們用Wireshark抓包時(shí),上面顯示的seq確實(shí)從0開(kāi)始的寡具,這是因?yàn)閃ireshark等抓包軟件為了讓seq和ack展示更直觀秤茅,自動(dòng)幫我們減去了初始順序號(hào) ISN,當(dāng)然也可以設(shè)置為直接展示真正的seq和ack童叠,那就看著比較亂了框喳,貼一張Wireshark處理后的seq和ack變化過(guò)程圖:
圖中前三步即TCP的三次握手,之后是數(shù)據(jù)傳輸厦坛∥蹇澹可以結(jié)合該圖去更好的理解本文。