tcp/udp是屬于運(yùn)輸層的兩個(gè)重要協(xié)議:
(1)用戶數(shù)據(jù)報(bào)協(xié)議UDP码秉。
(2)傳輸控制協(xié)議TCP。
1.UDP的主要特點(diǎn)
(1) UDP是無連接的矮燎,即發(fā)送數(shù)據(jù)之前不需要建立連接定血,因此減少了開銷和發(fā)送數(shù)據(jù)之前的時(shí)延。
(2) UDP使用盡最大努力交付诞外,即不保證可靠交付澜沟,因此主機(jī)不需要維持復(fù)雜的連接狀態(tài)表。
(3) UDP是面向報(bào)文的峡谊。發(fā)送方的UDP對應(yīng)用程序交下來的報(bào)文茫虽,在添加首部后就向下交付IP層刊苍。UDP對應(yīng)用層交下來的報(bào)文,既不合并濒析,也不拆分正什,而是保留這些報(bào)文的邊界。因此号杏,應(yīng)用程序必須選擇合適大小的報(bào)文埠忘。
(4) UDP沒有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)的擁塞不會使源主機(jī)的發(fā)送速率降低馒索。很多的實(shí)時(shí)應(yīng)用(如IP電話莹妒、實(shí)時(shí)視頻會議等)要去源主機(jī)以恒定的速率發(fā)送數(shù)據(jù),并且允許在網(wǎng)絡(luò)發(fā)生擁塞時(shí)丟失一些數(shù)據(jù)绰上,但卻不允許數(shù)據(jù)有太多的時(shí)延旨怠。UDP正好符合這種要求。
(5) UDP支持一對一蜈块、一對多鉴腻、多對一和多對多的交互通信。
(6) UDP的首部開銷小百揭,只有8個(gè)字節(jié)爽哎,比TCP的20個(gè)字節(jié)的首部要短。
注意:
(1) 不使用擁塞控制功能的UDP有可能會引起網(wǎng)絡(luò)產(chǎn)生嚴(yán)重的擁塞問題器一。
(2) 一些使用UDP的實(shí)時(shí)應(yīng)用進(jìn)程本身可以在不影響應(yīng)用的實(shí)時(shí)性的前提下课锌,增加一些提高可靠性的措施,如采用前向糾錯或重傳已丟失的報(bào)文祈秕。
UDP的首部格式
用戶數(shù)據(jù)報(bào)UDP有兩個(gè)字段:數(shù)據(jù)字段和首部字段渺贤。首部字段很簡單,只有8個(gè)字節(jié)请毛,由四個(gè)字段組成志鞍,每個(gè)字段的長度都是兩個(gè)字節(jié)。各字段的意義如下:
(1) 源端口 源端口號方仿。在需要對方回信時(shí)選用固棚。不需要時(shí)可用全0。
(2) 目的端口 目的端口號仙蚜。 這在終點(diǎn)交付報(bào)文時(shí)必須要使用到。
(3) 長度 UDP用戶數(shù)據(jù)報(bào)的長度鳍征,其最小值是8(僅有首部)
(4) 檢驗(yàn)和 檢測UDP用戶數(shù)據(jù)報(bào)在傳輸中是否有錯黍翎。有錯就丟棄面徽。
一個(gè)UDP模塊必須提供產(chǎn)生和驗(yàn)證檢驗(yàn)和的功能艳丛,但是一個(gè)應(yīng)用程序在使用UDP服務(wù)時(shí)匣掸,可以自由選擇是否要求產(chǎn)生校檢和。在計(jì)算校檢和時(shí)氮双,要在UDP用戶數(shù)據(jù)報(bào)之前增加12字節(jié)的偽首部碰酝。校檢和就是按照這個(gè)臨時(shí)的UDP用戶數(shù)據(jù)報(bào)來計(jì)算的。
UDP計(jì)算校檢和的方法和計(jì)算IP數(shù)據(jù)報(bào)首部校檢和的方法相似戴差。但不同的是:IP數(shù)據(jù)報(bào)的校檢和只校檢IP數(shù)據(jù)報(bào)的首部送爸,但UDP的校檢和使把首部和數(shù)據(jù)部分一起都校檢。
UDP的復(fù)用和分用
當(dāng)運(yùn)輸層從IP層收到UDP數(shù)據(jù)報(bào)時(shí)暖释,就根據(jù)首部中的目的端口袭厂,把UDP數(shù)據(jù)報(bào)通過相應(yīng)的端口,上交到最后的終點(diǎn)——應(yīng)用進(jìn)程球匕。下圖是UDP基于端口分用的示意圖纹磺。
基于端口的復(fù)用示意圖與上圖相似,只是數(shù)據(jù)報(bào)的傳輸方向相反亮曹。
如果接收方UDP發(fā)現(xiàn)收到的報(bào)文中的目的端口號不正確(即不存在對應(yīng)于該端口號的應(yīng)用進(jìn)程)橄杨,就丟棄該報(bào)文,并由網(wǎng)際控制報(bào)文協(xié)議ICMP發(fā)送“端口不可達(dá)”差錯報(bào)文給發(fā)送方照卦。
2.tcp的主要特點(diǎn)
(1)TCP是面向連接的運(yùn)輸層協(xié)議式矫。就是說,引用在使用TCP協(xié)議之前役耕,必須先建立TCP連接
(2)每一條TCP連接只能有兩個(gè)端點(diǎn)采转,每一條TCP只能是點(diǎn)對點(diǎn)的
(3)TCP提供可靠交付的服務(wù)。通過TCP連接傳送的數(shù)據(jù)瞬痘,無差錯氏义、不丟失、不重復(fù)图云、并且按序到達(dá)
(4)TCP提供全雙工通信惯悠。允許通信雙方的引用進(jìn)程在任何時(shí)候都發(fā)送數(shù)據(jù)。
(5)面向字節(jié)流竣况。
可靠傳輸?shù)墓ぷ髟?/h4>
(1)以字節(jié)為單位的滑動窗口
(2)超時(shí)重傳
現(xiàn)在假設(shè)A是發(fā)送方克婶,B是接收方,現(xiàn)假定A收到了B發(fā)來的確認(rèn)報(bào)文段丹泉,期中窗口為20情萤,確認(rèn)號是31(表明B期望收到的下一個(gè)序號是31,而序號30為止的數(shù)據(jù)已經(jīng)收到)摹恨,根據(jù)這兩個(gè)數(shù)據(jù)筋岛,A就可以構(gòu)造自己的發(fā)送窗口。如下圖:
現(xiàn)假定A發(fā)送了序號為31~41的數(shù)據(jù)晒哄。這時(shí)發(fā)送窗口的位置并未改變睁宰,但是發(fā)送窗口內(nèi)靠后面有11個(gè)字節(jié)表示已發(fā)送但是未收到確認(rèn)肪获,而發(fā)送窗口內(nèi)靠前面的9個(gè)字節(jié)是允許發(fā)送但尚未發(fā)送的。
從上述可知描述一個(gè)窗口需要三個(gè)指針P1,P2,P3柒傻。
再看一下B的窗口孝赫,B的接收窗口的大小是20,在接收窗口外面红符,到30號為止的數(shù)據(jù)表示已經(jīng)發(fā)送過確認(rèn)青柄,并且交付主機(jī)了。因此在B可以不再保留這些數(shù)據(jù)预侯。接收窗口內(nèi)的序號31~50是允許接收的致开。在上面的圖5-16中,B收到了序號為32和33 的數(shù)據(jù)萎馅,這些數(shù)據(jù)沒有按序到達(dá)喇喉,因?yàn)?1的數(shù)據(jù)沒有收到,請注意B只能對按序號收到的數(shù)據(jù)中的最高序號給出確認(rèn)校坑,因此B發(fā)送的確認(rèn)報(bào)文段中的確認(rèn)號仍然是31拣技。
現(xiàn)在假定B收到31的數(shù)據(jù),并把序號為31~33的數(shù)據(jù)交付主機(jī)耍目,然后B刪除這些數(shù)據(jù)膏斤。接著把窗口向前移動3個(gè)序號,(圖5-17)邪驮,同時(shí)給A發(fā)送確認(rèn)莫辨,期中窗口的值仍然是20,但確認(rèn)號是34毅访。這表明B已經(jīng)收到了到序號33為止的數(shù)據(jù)沮榜。我們注意到,B還接收到了沒按序號到達(dá)的37,38和40的數(shù)據(jù)喻粹,但這些都沒有按序到達(dá)蟆融,只能暫時(shí)放在接收窗口中。A收到B的確認(rèn)后守呜,就可以把發(fā)送窗口向前滑動3個(gè)序號了型酥。
A繼續(xù)發(fā)送完序號42~53的數(shù)據(jù),由于A發(fā)送窗口已滿查乒,可用窗口減小到0弥喉,因此必須停止發(fā)送。請注意玛迄,存在下面的可能性由境,就是發(fā)送窗口內(nèi)的數(shù)據(jù)都已經(jīng)正確到達(dá)B,B也早已發(fā)出了確認(rèn)蓖议。但不幸的是虏杰,所有這些確認(rèn)都滯留在網(wǎng)絡(luò)中讥蟆。沒有收到B的確認(rèn)時(shí),A不能猜測B收到了嘹屯,為了保證可靠傳輸,A只能認(rèn)為B還沒有收到這些數(shù)據(jù)从撼。于是A經(jīng)過一段時(shí)間后(超時(shí)計(jì)時(shí)器控制)就重傳這部分的數(shù)據(jù)州弟,重新設(shè)置超時(shí)計(jì)時(shí)器。直到收到B的確認(rèn)為止低零。
tcp首部格式
TCP雖然是面向字節(jié)流的婆翔,但TCP傳送的數(shù)據(jù)單元卻是報(bào)文段。一個(gè)TCP報(bào)文段分為首部和數(shù)據(jù)兩部分掏婶,而TCP的全部功能體現(xiàn)在它首部中的各字段的作用啃奴。因此,我們需要詳細(xì)了解一下TCP首部各字段的作用雄妥。
TCP報(bào)文段首部的前20個(gè)字節(jié)是固定的(下圖)最蕾,后面有4n字節(jié)是根據(jù)需要而增加的選項(xiàng)(n是整數(shù))。因此TCP首部的最小長度是20字節(jié)老厌。
首部固定部分各字段意義如下:
1) 源端口和目的端口 各占2個(gè)字節(jié)瘟则,分別寫入源端口和目的端口。
2) 序號 占4字節(jié)枝秤。序號范圍是【0醋拧,2^32 - 1】,共2^32 (即4294967296)個(gè)序號淀弹。序號增加到2^32-1后丹壕,下一個(gè)序號就又回到0。也就是說薇溃,序號使用mod 2^32運(yùn)算菌赖。TCP是面向字節(jié)流的。在一個(gè)TCP連接中傳送的字節(jié)流中的每一個(gè)字節(jié)都按順序編號沐序。整個(gè)要傳送的字節(jié)流的起始序號必須在連接建立時(shí)設(shè)置盏袄。首部中的序號字段值則是指的是本報(bào)文段所發(fā)送的數(shù)據(jù)的第一個(gè)字節(jié)的序號。例如薄啥,一報(bào)文段的序號是301辕羽,而接待的數(shù)據(jù)共有100字節(jié)。這就表明:本報(bào)文段的數(shù)據(jù)的第一個(gè)字節(jié)的序號是301垄惧,最后一個(gè)字節(jié)的序號是400刁愿。顯然,下一個(gè)報(bào)文段(如果還有的話)的數(shù)據(jù)序號應(yīng)當(dāng)從401開始到逊,即下一個(gè)報(bào)文段的序號字段值應(yīng)為401铣口。這個(gè)字段的序號也叫“報(bào)文段序號”滤钱。
3) 確認(rèn)號 占4字節(jié),是期望收到對方下一個(gè)報(bào)文段的第一個(gè)數(shù)據(jù)字節(jié)的序號脑题。例如件缸,B正確收到了A發(fā)送過來的一個(gè)報(bào)文段,其序號字段值是501叔遂,而數(shù)據(jù)長度是200字節(jié)(序號501~700)他炊,這表明B正確收到了A發(fā)送的到序號700為止的數(shù)據(jù)。因此已艰,B期望收到A的下一個(gè)數(shù)據(jù)序號是701痊末,于是B在發(fā)送給A的確認(rèn)報(bào)文段中把確認(rèn)號置為701。注意哩掺,現(xiàn)在確認(rèn)號不是501凿叠,也不是700,而是701嚼吞。 總之:若確認(rèn)號為= N盒件,則表明:到序號N-1為止的所有數(shù)據(jù)都已正確收到。
4) 數(shù)據(jù)偏移 占4位舱禽,它指出TCP報(bào)文段的數(shù)據(jù)起始處距離TCP報(bào)文段的起始處有多遠(yuǎn)履恩。這個(gè)字段實(shí)際上是指出TCP報(bào)文段的首部長度。由于首部中還有長度不確定的選項(xiàng)字段呢蔫,因此數(shù)據(jù)偏移字段是必要的切心,但應(yīng)注意,“數(shù)據(jù)偏移”的單位是32位字(即以4字節(jié)的字為計(jì)算單位)片吊。由于4位二進(jìn)制數(shù)能表示的最大十進(jìn)制數(shù)字是15绽昏,因此數(shù)據(jù)偏移的最大值是60字節(jié),這也是TCP首部的最大字節(jié)(即選項(xiàng)長度不能超過40字節(jié))俏脊。
5) 保留 占6位全谤,保留為今后使用,但目前應(yīng)置為0 爷贫。
下面有6個(gè)控制位认然,用來說明本報(bào)文段的性質(zhì)。
6) 緊急URG(URGent) 當(dāng)URG=1時(shí)漫萄,表明緊急指針字段有效卷员。它告訴系統(tǒng)此報(bào)文段中有緊急數(shù)據(jù),應(yīng)盡快發(fā)送(相當(dāng)于高優(yōu)先級的數(shù)據(jù))腾务,而不要按原來的排隊(duì)順序來傳送毕骡。例如,已經(jīng)發(fā)送了很長的一個(gè)程序要在遠(yuǎn)地的主機(jī)上運(yùn)行。但后來發(fā)現(xiàn)了一些問題未巫,需要取消該程序的運(yùn)行窿撬,因此用戶從鍵盤發(fā)出中斷命令。如果不使用緊急數(shù)據(jù)叙凡,那么這兩個(gè)字符將存儲在接收TCP的緩存末尾劈伴。只有在所有的數(shù)據(jù)被處理完畢后這兩個(gè)字符才被交付接收方的應(yīng)用進(jìn)程。這樣做就浪費(fèi)了很多時(shí)間握爷。
當(dāng)URG置為1時(shí)跛璧,發(fā)送應(yīng)用進(jìn)程就告訴發(fā)送方的TCP有緊急數(shù)據(jù)要傳送。于是發(fā)送方TCP就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面饼拍,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍然是普通數(shù)據(jù)赡模。這時(shí)要與首部中緊急指針(Urgent Pointer)字段配合使用田炭。
7) 確認(rèn)ACK(ACKnowledgment) 僅當(dāng)ACK = 1時(shí)確認(rèn)號字段才有效师抄,當(dāng)ACK = 0時(shí)確認(rèn)號無效。TCP規(guī)定教硫,在連接建立后所有的傳送的報(bào)文段都必須把ACK置為1叨吮。
8) 推送 PSH(PuSH) 當(dāng)兩個(gè)應(yīng)用進(jìn)程進(jìn)行交互式的通信時(shí),有時(shí)在一端的應(yīng)用進(jìn)程希望在鍵入一個(gè)命令后立即就能收到對方的響應(yīng)瞬矩。在這種情況下茶鉴,TCP就可以使用推送(push)操作。這時(shí)景用,發(fā)送方TCP把PSH置為1涵叮,并立即創(chuàng)建一個(gè)報(bào)文段發(fā)送出去。接收方TCP收到PSH=1的報(bào)文段伞插,就盡快地(即“推送”向前)交付接收應(yīng)用進(jìn)程割粮。而不用再等到整個(gè)緩存都填滿了后再向上交付。
9) 復(fù)位RST(ReSeT) 當(dāng)RST=1時(shí)媚污,表名TCP連接中出現(xiàn)了嚴(yán)重錯誤(如由于主機(jī)崩潰或其他原因)舀瓢,必須釋放連接,然后再重新建立傳輸連接耗美。RST置為1還用來拒絕一個(gè)非法的報(bào)文段或拒絕打開一個(gè)連接京髓。
10) 同步SYN(SYNchronization) 在連接建立時(shí)用來同步序號。當(dāng)SYN=1而ACK=0時(shí)商架,表明這是一個(gè)連接請求報(bào)文段堰怨。對方若同意建立連接,則應(yīng)在響應(yīng)的報(bào)文段中使SYN=1和ACK=1蛇摸,因此SYN置為1就表示這是一個(gè)連接請求或連接接受報(bào)文诚些。
11) 終止FIN(FINis,意思是“完”“終”) 用來釋放一個(gè)連接。當(dāng)FIN=1時(shí)诬烹,表明此報(bào)文段的發(fā)送發(fā)的數(shù)據(jù)已發(fā)送完畢砸烦,并要求釋放運(yùn)輸連接。
12) 窗口 占2字節(jié)。窗口值是【0棕所,2^16-1】之間的整數(shù)褥符。窗口指的是發(fā)送本報(bào)文段的一方的接受窗口(而不是自己的發(fā)送窗口)。窗口值告訴對方:從本報(bào)文段首部中的確認(rèn)號算起颜说,接收方目前允許對方發(fā)送的數(shù)據(jù)量(以字節(jié)為單位)。之所以要有這個(gè)限制汰聋,是因?yàn)榻邮辗降臄?shù)據(jù)緩存空間是有限的门粪。總之烹困,窗口值作為接收方讓發(fā)送方設(shè)置其發(fā)送窗口的依據(jù)玄妈。
例如,發(fā)送了一個(gè)報(bào)文段髓梅,其確認(rèn)號是701拟蜻,窗口字段是1000.這就是告訴對方:“從701算起,我(即發(fā)送方報(bào)文段的一方)的接收緩存空間還可接受1000個(gè)字節(jié)數(shù)據(jù)(字節(jié)序號是701~1700)枯饿,你在給我發(fā)數(shù)據(jù)時(shí)酝锅,必須考慮到這一點(diǎn)∩莘剑”總之:窗口字段明確指出了現(xiàn)在允許對方發(fā)送的數(shù)據(jù)量搔扁。窗口值經(jīng)常在動態(tài)變化。
13) 檢驗(yàn)和 占2字節(jié)蟋字。檢驗(yàn)和字段檢驗(yàn)的范圍包括首部和數(shù)據(jù)這兩部分稿蹲。和UDP用戶數(shù)據(jù)報(bào)一樣,在計(jì)算檢驗(yàn)和時(shí)愉老,要在TCP報(bào)文段的前面加上12字節(jié)的偽首部场绿。偽首部的格式和UDP用戶數(shù)據(jù)報(bào)的偽首部一樣。但應(yīng)把偽首部第4個(gè)字段中的17改為6(TCP的協(xié)議號是6)嫉入;把第5字段中的UDP中的長度改為TCP長度焰盗。接收方收到此報(bào)文段后,仍要加上這個(gè)偽首部來計(jì)算檢驗(yàn)和咒林。若使用TPv6,則相應(yīng)的偽首部也要改變熬拒。
14) 緊急指針 占2字節(jié)。緊急指針僅在URG=1時(shí)才有意義垫竞,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)(緊急數(shù)據(jù)結(jié)束后就是普通數(shù)據(jù)) 澎粟。因此蛀序,在緊急指針指出了緊急數(shù)據(jù)的末尾在報(bào)文段中的位置。當(dāng)所有緊急數(shù)據(jù)都處理完時(shí)活烙,TCP就告訴應(yīng)用程序恢復(fù)到正常操作徐裸。值得注意的是,即使窗口為0時(shí)也可以發(fā)送緊急數(shù)據(jù)啸盏。
15) 選項(xiàng) 長度可變重贺,最長可達(dá)4字節(jié)。當(dāng)沒有使用“選項(xiàng)”時(shí)回懦,TCP的首部長度是20字節(jié)气笙。
TCP最初只規(guī)定了一種選項(xiàng),即最大報(bào)文段長度MSS(Maximum Segment Szie)怯晕。注意MSS這個(gè)名詞含義潜圃。MSS是每一個(gè)TCP報(bào)文段中的數(shù)據(jù)字段的最大長度。數(shù)據(jù)字段加上TCP首部才等于整個(gè)的TCP報(bào)文段舟茶。所以MSS并不是整個(gè)TCP報(bào)文段的最大長度谭期,而是“TCP報(bào)文段長度減去TCP首部長度”。
為什么要規(guī)定一個(gè)最大報(bào)文長度MSS呢稚晚?這并不是考慮接受方的接收緩存可能存放不下TCP報(bào)文段中的數(shù)據(jù)崇堵。實(shí)際上型诚,MSS與接收窗口值沒有關(guān)系客燕。我們知道,TCP報(bào)文段的數(shù)據(jù)部分狰贯,至少要加上40字節(jié)的首部(TCP首部20字節(jié)和IP首部20字節(jié)也搓,這里還沒有考慮首部中的可選部分)才能組裝成一個(gè)IP數(shù)據(jù)報(bào)。若選擇較小的MSS長度涵紊,網(wǎng)絡(luò)的利用率就降低傍妒。設(shè)想在極端情況下,當(dāng)TCP報(bào)文段只含有1字節(jié)的數(shù)據(jù)時(shí)摸柄,在IP層傳輸?shù)臄?shù)據(jù)報(bào)的開銷至少有40字節(jié)(包括TCP報(bào)文段的首部和IP數(shù)據(jù)報(bào)的首部)颤练。這樣,對網(wǎng)絡(luò)的利用率就不會超過1/41驱负。到了數(shù)據(jù)鏈路層還要加上一些開銷嗦玖。但反過來,若TCP報(bào)文段非常長跃脊,那么在IP層傳輸時(shí)就有可能要分解成多個(gè)短數(shù)據(jù)報(bào)片宇挫。在終點(diǎn)要把收到的各個(gè)短數(shù)據(jù)報(bào)片組成成原來的TCP報(bào)文段,當(dāng)傳輸出錯時(shí)還要進(jìn)行重傳酪术,這些也都會使開銷增大器瘪。
因此,MSS應(yīng)盡可能大些,只要在IP層傳輸時(shí)不需要分片就行橡疼。由于IP數(shù)據(jù)報(bào)所經(jīng)歷的路徑是動態(tài)變化的援所,因此在這條路徑上確定的不需要的分片的MSS,如果改走另一條路徑就可能需要進(jìn)行分片欣除。因此最佳的MSS是很難確定的任斋。在連接過程中,雙方都把自己能夠支持的MSS寫入這一字段耻涛,以后就按照這個(gè)數(shù)值傳輸數(shù)據(jù)废酷,兩個(gè)傳送方向可以有不同的MSS值。若主機(jī)未填寫這一項(xiàng)抹缕,則MSS的默認(rèn)值是536字節(jié)長澈蟆。因此,所有在互聯(lián)網(wǎng)上的主機(jī)都應(yīng)該接受的報(bào)文段長度是536+20(固定首部長度)=556字節(jié)卓研。
后來又增加了幾個(gè)選項(xiàng)如窗口擴(kuò)大選項(xiàng)趴俘、時(shí)間戳選項(xiàng)等。
窗口擴(kuò)大選項(xiàng)是為了擴(kuò)大窗口奏赘。我們知道寥闪,TCP首部中窗口字段長度是16位,因此最大的窗口大小為64K字節(jié)磨淌。雖然這對早期的網(wǎng)絡(luò)是足夠用的疲憋,但對于包含衛(wèi)星信道的網(wǎng)絡(luò),傳播時(shí)延和寬帶都很大梁只,要獲得高吞吐量需要更大的窗口大小缚柳。
窗口擴(kuò)大選項(xiàng)占3字節(jié),其中有一個(gè)字節(jié)表示移位值S搪锣。新的窗口值等于TCP首部中的窗口位數(shù)從16增大到(16+S)秋忙。移位值允許使用的最大值是14,相當(dāng)于窗口最大值增大到2^(16+14)-1 =2^30-1构舟。
窗口擴(kuò)大選項(xiàng)可以在雙方初始建立TCP連接時(shí)進(jìn)行協(xié)商灰追。如果連接的某一端實(shí)現(xiàn)了窗口擴(kuò)大,當(dāng)它不再需要擴(kuò)大其窗口時(shí)狗超,可發(fā)送S=0選項(xiàng)弹澎,使窗口大小回到16。
時(shí)間戳選項(xiàng)占10字節(jié)抡谐,其中最主要的字段是時(shí)間戳字段(4字節(jié))和時(shí)間戳回送回答字段(4字節(jié))裁奇。時(shí)間戳選項(xiàng)有以下兩個(gè)概念:
第一、 用來計(jì)算往返時(shí)間RTT麦撵。發(fā)送方在發(fā)送報(bào)文段時(shí)把當(dāng)前時(shí)鐘的時(shí)間值放入時(shí)間戳字段刽肠,接收方在確認(rèn)該報(bào)文段時(shí)把時(shí)間戳字段復(fù)制到時(shí)間戳回送回答字段溃肪。因此,發(fā)送方在收到確認(rèn)報(bào)文后音五,可以準(zhǔn)確地計(jì)算出RTT來惫撰。
第二、 用于處理TCP序號超過2^32 的情況躺涝,這又稱為防止序號繞回PAWS厨钻。我們知道,TCP報(bào)文段的序號只有32位坚嗜,而每增加2^32個(gè)序號就會重復(fù)使用原來用過的序號夯膀。當(dāng)使用高速網(wǎng)絡(luò)時(shí),在一次TCP連接的數(shù)據(jù)傳送中序號很可能被重復(fù)使用苍蔬。例如诱建,當(dāng)使用1.5Mbit/s的速度發(fā)送報(bào)文段時(shí),序號重復(fù)要6小時(shí)以上碟绑。但若用2.5Gbit/s的速率發(fā)送報(bào)文段俺猿,則不到14秒鐘序號就會重復(fù)。為了使接收方能夠把新的報(bào)文段和遲到很久的報(bào)文段區(qū)分開格仲,則可以在報(bào)文段中加上這種時(shí)間戳押袍。
tcp流量控制
流量控制方面主要有兩個(gè)要點(diǎn)需要掌握。一是TCP利用滑動窗口實(shí)現(xiàn)流量控制的機(jī)制凯肋;二是如何考慮流量控制中的傳輸效率谊惭。
-
流量控制
所謂流量控制,主要是接收方傳遞信息給發(fā)送方否过,使其不要發(fā)送數(shù)據(jù)太快午笛,是一種端到端的控制惭蟋。主要的方式就是返回的ACK中會包含自己的接收窗口的大小苗桂,并且利用大小來控制發(fā)送方的數(shù)據(jù)發(fā)送:
這里面涉及到一種情況,如果B已經(jīng)告訴A自己的緩沖區(qū)已滿告组,于是A停止發(fā)送數(shù)據(jù)煤伟;等待一段時(shí)間后,B的緩沖區(qū)出現(xiàn)了富余木缝,于是給A發(fā)送報(bào)文告訴A我的rwnd大小為400便锨,但是這個(gè)報(bào)文不幸丟失了,于是就出現(xiàn)A等待B的通知||B等待A發(fā)送數(shù)據(jù)的死鎖狀態(tài)我碟。為了處理這種問題放案,TCP引入了持續(xù)計(jì)時(shí)器(Persistence timer),當(dāng)A收到對方的零窗口通知時(shí)矫俺,就啟用該計(jì)時(shí)器吱殉,時(shí)間到則發(fā)送一個(gè)1字節(jié)的探測報(bào)文掸冤,對方會在此時(shí)回應(yīng)自身的接收窗口大小,如果結(jié)果仍未0友雳,則重設(shè)持續(xù)計(jì)時(shí)器稿湿,繼續(xù)等待。
- 傳遞效率
一個(gè)顯而易見的問題是:單個(gè)發(fā)送字節(jié)單個(gè)確認(rèn)押赊,和窗口有一個(gè)空余即通知發(fā)送方發(fā)送一個(gè)字節(jié)饺藤,無疑增加了網(wǎng)絡(luò)中的許多不必要的報(bào)文(請想想為了一個(gè)字節(jié)數(shù)據(jù)而添加的40字節(jié)頭部吧!)流礁,所以我們的原則是盡可能一次多發(fā)送幾個(gè)字節(jié)涕俗,或者窗口空余較多的時(shí)候通知發(fā)送方一次發(fā)送多個(gè)字節(jié)。對于前者我們廣泛使用Nagle算法神帅,即:
*1. 若發(fā)送應(yīng)用進(jìn)程要把發(fā)送的數(shù)據(jù)逐個(gè)字節(jié)地送到TCP的發(fā)送緩存咽袜,則發(fā)送方就把第一個(gè)數(shù)據(jù)字節(jié)先發(fā)送出去枕稀,把后面的字節(jié)先緩存起來凹联;
*2. 當(dāng)發(fā)送方收到第一個(gè)字節(jié)的確認(rèn)后(也得到了網(wǎng)絡(luò)情況和對方的接收窗口大邪氖纭),再把緩沖區(qū)的剩余字節(jié)組成合適大小的報(bào)文發(fā)送出去;
*3. 當(dāng)?shù)竭_(dá)的數(shù)據(jù)已達(dá)到發(fā)送窗口大小的一半或以達(dá)到報(bào)文段的最大長度時(shí),就立即發(fā)送一個(gè)報(bào)文段;
對于后者我們往往的做法是讓接收方等待一段時(shí)間耳璧,或者接收方獲得足夠的空間容納一個(gè)報(bào)文段或者等到接受緩存有一半空閑的時(shí)候,再通知發(fā)送方發(fā)送數(shù)據(jù)展箱。
tcp擁塞控制
網(wǎng)絡(luò)中的鏈路容量和交換結(jié)點(diǎn)中的緩存和處理機(jī)都有著工作的極限攀隔,當(dāng)網(wǎng)絡(luò)的需求超過它們的工作極限時(shí)婴栽,就出現(xiàn)了擁塞轰枝。擁塞控制就是防止過多的數(shù)據(jù)注入到網(wǎng)絡(luò)中,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不致過載。常用的方法就是:
- 慢開始、擁塞控制
- 快重傳、快恢復(fù)
一切的基礎(chǔ)還是慢開始,這種方法的思路是這樣的:
- 發(fā)送方維持一個(gè)叫做“擁塞窗口”的變量缭贡,該變量和接收端口共同決定了發(fā)送者的發(fā)送窗口眶俩;
- 當(dāng)主機(jī)開始發(fā)送數(shù)據(jù)時(shí)线罕,避免一下子將大量字節(jié)注入到網(wǎng)絡(luò)袄琳,造成或者增加擁塞窗轩,選擇發(fā)送一個(gè)1字節(jié)的試探報(bào)文;
- 當(dāng)收到第一個(gè)字節(jié)的數(shù)據(jù)的確認(rèn)后舌缤,就發(fā)送2個(gè)字節(jié)的報(bào)文;
- 若再次收到2個(gè)字節(jié)的確認(rèn)囚似,則發(fā)送4個(gè)字節(jié)剩拢,依次遞增2的指數(shù)級;
- 最后會達(dá)到一個(gè)提前預(yù)設(shè)的“慢開始門限”饶唤,比如24徐伐,即一次發(fā)送了24個(gè)分組,此時(shí)遵循下面的條件判定:
*1. cwnd < ssthresh募狂, 繼續(xù)使用慢開始算法办素;
*2. cwnd > ssthresh,停止使用慢開始算法熬尺,改用擁塞避免算法摸屠;
*3. cwnd = ssthresh,既可以使用慢開始算法粱哼,也可以使用擁塞避免算法季二; - 所謂擁塞避免算法就是:每經(jīng)過一個(gè)往返時(shí)間RTT就把發(fā)送方的擁塞窗口+1,即讓擁塞窗口緩慢地增大揭措,按照線性規(guī)律增長胯舷;
-
當(dāng)出現(xiàn)網(wǎng)絡(luò)擁塞,比如丟包時(shí)绊含,將慢開始門限設(shè)為原先的一半桑嘶,然后將cwnd設(shè)為1,執(zhí)行慢開始算法(較低的起點(diǎn)躬充,指數(shù)級增長)逃顶;
上述方法的目的是在擁塞發(fā)生時(shí)循序減少主機(jī)發(fā)送到網(wǎng)絡(luò)中的分組數(shù),使得發(fā)生擁塞的路由器有足夠的時(shí)間把隊(duì)列中積壓的分組處理完畢充甚。慢開始和擁塞控制算法常常作為一個(gè)整體使用以政,而快重傳和快恢復(fù)則是為了減少因?yàn)閾砣麑?dǎo)致的數(shù)據(jù)包丟失帶來的重傳時(shí)間,從而避免傳遞無用的數(shù)據(jù)到網(wǎng)絡(luò)伴找∮快重傳的機(jī)制是:
- 接收方建立這樣的機(jī)制,如果一個(gè)包丟失技矮,則對后續(xù)的包繼續(xù)發(fā)送針對該包的重傳請求抖誉;
- 一旦發(fā)送方接收到三個(gè)一樣的確認(rèn),就知道該包之后出現(xiàn)了錯誤衰倦,立刻重傳該包袒炉;
- 此時(shí)發(fā)送方開始執(zhí)行“快恢復(fù)”算法:
- 慢開始門限減半;
- cwnd設(shè)為慢開始門限減半后的數(shù)值耿币;
-
執(zhí)行擁塞避免算法(高起點(diǎn)梳杏,線性增長);
tcp連接管理
1. 連接過程
tcp建立連接的過程也叫三次握手:假設(shè)A是客戶端淹接,B是服務(wù)器十性,A主動打開連接,B被動打開連接塑悼。
- 第一次握手:
A向B發(fā)起連接,這時(shí)tcp協(xié)議首部的同部位SYN=1劲适,同時(shí)選擇一個(gè)初始序號seq=x。tcp規(guī)定厢蒜,SYN=1的報(bào)文段不能攜帶數(shù)據(jù)霞势,但是要消耗一個(gè)序號。這時(shí)tcp客戶端進(jìn)入SYN_SEND狀態(tài)斑鸦。 - 第二次握手:
B收到連接請求后愕贡,如同意建立連接,則向A發(fā)送確認(rèn)巷屿。在確認(rèn)報(bào)文段中設(shè)置SYN=1固以,ACK=1,確認(rèn)號ack=x+1嘱巾,同時(shí)也為自己選擇一個(gè)初始序號seq=y憨琳。這個(gè)報(bào)文段也不能攜帶數(shù)據(jù),但同樣也要消耗一個(gè)序號旬昭。這是服務(wù)器進(jìn)入SYN_RECV狀態(tài)篙螟。 - 第三次握手
tcp客戶端收到B的確認(rèn)后,還要向B給出確認(rèn)问拘,確認(rèn)報(bào)文段的ACK=1遍略,確認(rèn)號seq=y+1,而自己的序號為ack=x+1骤坐。ACK報(bào)文段可以攜帶數(shù)據(jù)绪杏,但如果沒有攜帶數(shù)據(jù)則不消耗序號,這種情況下或油,下個(gè)數(shù)據(jù)報(bào)文段的序號仍然是seq=x+1寞忿。這時(shí)tcp建立連接,A進(jìn)入ESTABLISHED狀態(tài)顶岸。
tcp連接過程圖:
握手中斷
- 第一次握手中斷: A發(fā)送給B的SYN中斷腔彰,A會周期性超時(shí)重傳,直到A收到B的確認(rèn)響應(yīng)辖佣。
- 第二次握手中斷: B發(fā)送給A的SYN霹抛、ACK中斷,B會周期性超時(shí)重傳卷谈,直到B收到A的確認(rèn)響應(yīng)杯拐。
- 第三次握手中斷: A發(fā)送給B的ACK中斷,A不會重傳。超時(shí)后端逼,B會重傳SYN信號(即回到第二次握手)朗兵,直到B收到A的確認(rèn)響應(yīng)。
為什么要三次握手
以下是兩種比較權(quán)威說法:
- 在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是“為了防止已失效的連接請求報(bào)文段突然又傳送到了服務(wù)端顶滩,因而產(chǎn)生錯誤”余掖。在另一部經(jīng)典的《計(jì)算機(jī)網(wǎng)絡(luò)》一書中講“三次握手”的目的是為了解決“網(wǎng)絡(luò)中存在延遲的重復(fù)分組”的問題。這兩種不用的表述其實(shí)闡明的是同一個(gè)問題礁鲁。謝希仁版《計(jì)算機(jī)網(wǎng)絡(luò)》中的例子是這樣的盐欺,“已失效的連接請求報(bào)文段”的產(chǎn)生在這樣一種情況下:client發(fā)出的第一個(gè)連接請求報(bào)文段并沒有丟失,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長時(shí)間的滯留了仅醇,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server冗美。本來這是一個(gè)早已失效的報(bào)文段。但server收到此失效的連接請求報(bào)文段后析二,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請求粉洼。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接甲抖。假設(shè)不采用“三次握手”漆改,那么只要server發(fā)出確認(rèn),新的連接就建立了准谚。由于現(xiàn)在client并沒有發(fā)出建立連接的請求挫剑,因此不會理睬server的確認(rèn),也不會向server發(fā)送數(shù)據(jù)柱衔。但server卻以為新的運(yùn)輸連接已經(jīng)建立樊破,并一直等待client發(fā)來數(shù)據(jù)。這樣唆铐,server的很多資源就白白浪費(fèi)掉了哲戚。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生。例如剛才那種情況艾岂,client不會向server的確認(rèn)發(fā)出確認(rèn)顺少。server由于收不到確認(rèn),就知道client并沒有要求建立連接王浴〈嘌祝”
- 在Google Groups的TopLanguage中看到一帖討論TCP“三次握手”覺得很有意思。貼主提出“TCP建立連接為什么是三次握手氓辣?”的問題秒裕,在眾多回復(fù)中,有一條回復(fù)寫道:“這個(gè)問題的本質(zhì)是, 信道不可靠, 但是通信雙發(fā)需要就某個(gè)問題達(dá)成一致. 而要解決這個(gè)問題, 無論你在消息中包含什么信息, 三次通信是理論上的最小值. 所以三次握手不是TCP本身的要求, 而是為了滿足"在不可靠信道上可靠地傳輸信息"這一需求所導(dǎo)致的. 請注意這里的本質(zhì)需求,信道不可靠, 數(shù)據(jù)傳輸要可靠. 三次達(dá)到了, 那后面你想接著握手也好, 發(fā)數(shù)據(jù)也好, 跟進(jìn)行可靠信息傳輸?shù)男枨缶蜎]關(guān)系了. 因此,如果信道是可靠的, 即無論什么時(shí)候發(fā)出消息, 對方一定能收到, 或者你不關(guān)心是否要保證對方收到你的消息, 那就能像UDP那樣直接發(fā)送消息就可以了.”钞啸。
2. 斷開過程
tcp的斷開過程也叫四次揮手的過程几蜻。
假設(shè)Client端發(fā)起中斷連接請求喇潘,也就是發(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端扼褪,你的請求我收到了,但是我還沒準(zhǔn)備好粱栖,請繼續(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后依然沒有收到回復(fù),則證明Server端已正常關(guān)閉佛南,那好梗掰,我Client端也可以關(guān)閉連接了。Ok共虑,TCP連接就這樣關(guān)閉了愧怜!
斷開過程圖:
斷開過程
- A的應(yīng)用進(jìn)程先向其TCP發(fā)出連接釋放報(bào)文段(FIN=1,序號seq=u)妈拌,并停止再發(fā)送數(shù)據(jù)拥坛,主動關(guān)閉TCP連接蓬蝶,進(jìn)入FIN-WAIT-1(終止等待1)狀態(tài),等待B的確認(rèn)猜惋。
- B收到連接釋放報(bào)文段后即發(fā)出確認(rèn)報(bào)文段丸氛,(ACK=1,確認(rèn)號ack=u+1著摔,序號seq=v)缓窜,B進(jìn)入CLOSE-WAIT(關(guān)閉等待)狀態(tài),此時(shí)的TCP處于半關(guān)閉狀態(tài)谍咆,A到B的連接釋放禾锤。
- A收到B的確認(rèn)后,進(jìn)入FIN-WAIT-2(終止等待2)狀態(tài)摹察,等待B發(fā)出的連接釋放報(bào)文段恩掷。
- B沒有要向A發(fā)出的數(shù)據(jù),B發(fā)出連接釋放報(bào)文段(FIN=1供嚎,ACK=1黄娘,序號seq=w,確認(rèn)號ack=u+1)克滴,B進(jìn)入LAST-ACK(最后確認(rèn))狀態(tài)逼争,等待A的確認(rèn)。
- A收到B的連接釋放報(bào)文段后劝赔,對此發(fā)出確認(rèn)報(bào)文段(ACK=1誓焦,seq=u+1,ack=w+1)望忆,A進(jìn)入TIME-WAIT(時(shí)間等待)狀態(tài)罩阵。此時(shí)TCP未釋放掉,需要經(jīng)過時(shí)間等待計(jì)時(shí)器設(shè)置的時(shí)間2MSL后启摄,A才進(jìn)入CLOSED狀態(tài)稿壁。
為什么A在TIME-WAIT狀態(tài)必須等待2MSL的時(shí)間?
MSL最長報(bào)文段壽命Maximum Segment Lifetime歉备,MSL=2
答:兩個(gè)理由:
- 保證A發(fā)送的最后一個(gè)ACK報(bào)文段能夠到達(dá)B傅是。
這個(gè)ACK報(bào)文段有可能丟失,使得處于LAST-ACK狀態(tài)的B收不到對已發(fā)送的FIN+ACK報(bào)文段的確認(rèn)蕾羊,B超時(shí)重傳FIN+ACK報(bào)文段喧笔,而A能在2MSL時(shí)間內(nèi)收到這個(gè)重傳的FIN+ACK報(bào)文段,接著A重傳一次確認(rèn)龟再,重新啟動2MSL計(jì)時(shí)器书闸,最后A和B都進(jìn)入到CLOSED狀態(tài),若A在TIME-WAIT狀態(tài)不等待一段時(shí)間利凑,而是發(fā)送完ACK報(bào)文段后立即釋放連接浆劲,則無法收到B重傳的FIN+ACK報(bào)文段嫌术,所以不會再發(fā)送一次確認(rèn)報(bào)文段,則B無法正常進(jìn)入到CLOSED狀態(tài)牌借。
- 防止“已失效的連接請求報(bào)文段”出現(xiàn)在本連接中度气。
A在發(fā)送完最后一個(gè)ACK報(bào)文段后,再經(jīng)過2MSL膨报,就可以使本連接持續(xù)的時(shí)間內(nèi)所產(chǎn)生的所有報(bào)文段都從網(wǎng)絡(luò)中消失磷籍,使下一個(gè)新的連接中不會出現(xiàn)這種舊的連接請求報(bào)文段。
毕帜活計(jì)時(shí)器
除了時(shí)間等待計(jì)時(shí)器外院领,tcp還設(shè)置一個(gè)保活計(jì)時(shí)器晒旅。設(shè)想有這樣的情況:客戶端已主動跟服務(wù)端建立連接栅盲。但后來客戶端主機(jī)突然故障。顯然服務(wù)器以后就不能再收到客戶端發(fā)來的數(shù)據(jù)废恋。因此應(yīng)當(dāng)有措施使服務(wù)器不要白白等待下去。這就是卑羌模活計(jì)時(shí)器鱼鼓。服務(wù)器每收到一次客戶的數(shù)據(jù),就重新設(shè)置备帽啵活計(jì)時(shí)器迄本,時(shí)間的設(shè)置一般是2個(gè)小時(shí)。若兩個(gè)小時(shí)沒有收到一次客戶的數(shù)據(jù)课竣,服務(wù)器就發(fā)送一個(gè)探測報(bào)文段嘉赎,以后則每隔75分鐘發(fā)送一次,若一連發(fā)送十次仍然沒有響應(yīng)于樟,服務(wù)器就認(rèn)為客戶端出了故障公条,接著服務(wù)器就自己關(guān)閉這個(gè)鏈接。