ISO提出了(le)OSI分(fen)層(ceng)網絡(luo)(luo)模型,這種分(fen)層(ceng)模型是理論上的(de),TCP/IP最(zui)終實現了(le)一(yi)個(ge)分(fen)層(ceng)的(de)協議模型,每一(yi)個(ge)層(ceng)次(ci)對應一(yi)組(zu)網絡(luo)(luo)協議完成一(yi)組(zu)特定的(de)功能,該組(zu)網絡(luo)(luo)協議被(bei)其下的(de)層(ceng)次(ci)復用(yong)和(he)解復用(yong)。這就是分(fen)層(ceng)模型的(de)本質,最(zui)終所有的(de)邏輯(ji)被(bei)編碼到線纜或者(zhe)電磁波。
分層模型是(shi)(shi)很(hen)好理解的,然而對于每一(yi)(yi)(yi)(yi)層的協(xie)議(yi)(yi)(yi)(yi)設(she)計卻不(bu)是(shi)(shi)那么(me)容(rong)易。TCP/IP的漂亮之處(chu)在(zai)于:協(xie)議(yi)(yi)(yi)(yi)越往上層越復雜。我們(men)把網絡(luo)定(ding)義為(wei)(wei)互相連接在(zai)一(yi)(yi)(yi)(yi)起(qi)(qi)的設(she)備,網絡(luo)的本(ben)質(zhi)作用還(huan)是(shi)(shi)“端(duan)到端(duan)”的通(tong)信,然而希望互相通(tong)信的設(she)備并不(bu)一(yi)(yi)(yi)(yi)定(ding)要“直接”連接在(zai)一(yi)(yi)(yi)(yi)起(qi)(qi),因(yin)此(ci)(ci)必然需(xu)要一(yi)(yi)(yi)(yi)些中間的設(she)備負責轉(zhuan)發(fa)數據(ju),因(yin)此(ci)(ci)就(jiu)(jiu)把連接這些中間設(she)備的線纜上跑的協(xie)議(yi)(yi)(yi)(yi)定(ding)義為(wei)(wei)鏈(lian)(lian)路層協(xie)議(yi)(yi)(yi)(yi),實際(ji)上所謂鏈(lian)(lian)路其實就(jiu)(jiu)是(shi)(shi)始(shi)發(fa)與(yu)一(yi)(yi)(yi)(yi)個(ge)設(she)備,通(tong)過一(yi)(yi)(yi)(yi)根線,終止于另一(yi)(yi)(yi)(yi)個(ge)設(she)備。我們(men)把一(yi)(yi)(yi)(yi)條鏈(lian)(lian)路稱為(wei)(wei)“一(yi)(yi)(yi)(yi)跳”。因(yin)此(ci)(ci)一(yi)(yi)(yi)(yi)個(ge)端(duan)到端(duan)的網絡(luo)包含了“很(hen)多跳”。
2.TCP和IP協(xie)議
終止(zhi)于IP協(xie)議,我們已經(jing)可以完成一(yi)個(ge)端到端的通(tong)信,為(wei)(wei)何(he)(he)(he)還需要TCP協(xie)議?這是一(yi)個(ge)問題,理解了(le)這個(ge)問題,我們就(jiu)能理解TCP協(xie)議為(wei)(wei)何(he)(he)(he)成了(le)現(xian)在這個(ge)樣子,為(wei)(wei)何(he)(he)(he)如此“復雜”,為(wei)(wei)何(he)(he)(he)又如此簡單。
正如其名字所展示的(de)那樣(yang),TCP的(de)作用是(shi)傳(chuan)輸控制,也(ye)就是(shi)控制端(duan)到(dao)端(duan)的(de)傳(chuan)輸,那為何這種控制不在IP協(xie)議(yi)中實現的(de)。答案很簡單,那就是(shi)這會(hui)增加IP協(xie)議(yi)的(de)復雜性(xing),而IP協(xie)議(yi)需要的(de)就是(shi)簡單。這是(shi)什么原因(yin)造成的(de)呢?
首先我們認識一下(xia)為(wei)何IP協(xie)議是沙漏的(de)(de)細腰部分。它的(de)(de)下(xia)層是繁多(duo)(duo)的(de)(de)鏈(lian)路(lu)層協(xie)議,這(zhe)些鏈(lian)路(lu)提供了(le)相互(hu)截(jie)然(ran)不(bu)同且相差很遠的(de)(de)語(yu)義,為(wei)了(le)互(hu)聯(lian)這(zhe)些異構的(de)(de)網(wang)絡(luo),我們需要一個網(wang)絡(luo)層協(xie)議起碼要提供一些適(shi)配的(de)(de)功能,另(ling)外它必然(ran)不(bu)能提供太多(duo)(duo)的(de)(de)“保證(zheng)性服務”,因(yin)為(wei)上層的(de)(de)保證(zheng)性依(yi)賴下(xia)層的(de)(de)約束(shu)性更強(qiang)的(de)(de)保證(zheng)性,你永(yong)遠無法在一個100M吞吐(tu)量(liang)的(de)(de)鏈(lian)路(lu)之(zhi)上實現(xian)的(de)(de)IP協(xie)議保證(zheng)1000M的(de)(de)吞吐(tu)量(liang)...
IP協(xie)議(yi)設(she)計為分(fen)組轉(zhuan)發(fa)協(xie)議(yi),每一(yi)(yi)跳都要經(jing)過(guo)(guo)一(yi)(yi)個(ge)中間節點(dian),路由的設(she)計是TCP/IP網(wang)絡的另一(yi)(yi)大創舉,這(zhe)樣,IP協(xie)議(yi)就無需方向性,路由信息和(he)協(xie)議(yi)本(ben)身不(bu)再強關聯(lian),它們僅僅通(tong)過(guo)(guo)IP地址(zhi)來關聯(lian),因(yin)此,IP協(xie)議(yi)更加簡單。路由器作為中間節點(dian)也不(bu)能太復雜,這(zhe)涉及到成(cheng)本(ben)問題,因(yin)此路由器只負責選路以(yi)及轉(zhuan)發(fa)數(shu)據包。
因此(ci)傳輸控(kong)制協(xie)議(yi)必然(ran)需要在端點實現。在我(wo)們詳談TCP協(xie)議(yi)之前,首(shou)先要看一下(xia)它不(bu)能做什么,由(you)于(yu)IP協(xie)議(yi)不(bu)提供保(bao)證(zheng),TCP也(ye)不(bu)能提供依(yi)賴于(yu)IP下(xia)層(ceng)(ceng)鏈路的(de)(de)這(zhe)種保(bao)證(zheng),比如帶寬,比如時延,這(zhe)些(xie)(xie)都是(shi)鏈路層(ceng)(ceng)決定的(de)(de),既(ji)然(ran)IP協(xie)議(yi)無法修(xiu)補,TCP也(ye)不(bu)能,然(ran)而它卻能修(xiu)正始于(yu)IP層(ceng)(ceng)的(de)(de)一些(xie)(xie)“不(bu)可保(bao)證(zheng)性(xing)質(zhi)”,這(zhe)些(xie)(xie)性(xing)質(zhi)包括IP層(ceng)(ceng)的(de)(de)不(bu)可靠,IP層(ceng)(ceng)的(de)(de)不(bu)按順(shun)序,IP層(ceng)(ceng)的(de)(de)無方向/無連接。
將該小節總結一(yi)下,TCP/IP 模型從下往(wang)上(shang),功(gong)能(neng)增(zeng)加(jia),需要實現的(de)設備減少,然而設備的(de)復(fu)雜性(xing)卻在增(zeng)加(jia),這(zhe)樣(yang)保證了成(cheng)本的(de)最小化,至于性(xing)能(neng)或者因素,靠軟件來調節吧(ba),TCP協議(yi)就是這(zhe)樣(yang)的(de)軟件,實際上(shang)最開始的(de)時(shi)候,TCP并不考慮性(xing)能(neng),效率,公平性(xing),正是考慮了這(zhe)些,TCP協議(yi)才復(fu)雜了起來。
3.TCP協議
這是一(yi)個(ge)純(chun)軟件協(xie)(xie)議,為何將其設計上兩個(ge)端(duan)點,參見(jian)上一(yi)小節,本節詳述TCP協(xie)(xie)議,中間也穿(chuan)插一(yi)些簡短的(de)論述。
3.1.TCP協議
確切的(de)說,TCP協(xie)(xie)議(yi)有兩重身份,作為(wei)網絡(luo)(luo)協(xie)(xie)議(yi),它(ta)(ta)彌補(bu)了(le)(le)(le)IP協(xie)(xie)議(yi)盡力而為(wei)服務(wu)的(de)不足,實現了(le)(le)(le)有連接,可(ke)靠傳輸,報文按序到達。作為(wei)一(yi)(yi)個(ge)(ge)(ge)主機(ji)(ji)軟件,它(ta)(ta)和(he)(he) UDP以及左(zuo)右的(de)傳輸層協(xie)(xie)議(yi)隔離了(le)(le)(le)主機(ji)(ji)服務(wu)和(he)(he)網絡(luo)(luo),它(ta)(ta)們可(ke)以被看做(zuo)是(shi)一(yi)(yi)個(ge)(ge)(ge)多路(lu)(lu)復(fu)(fu)(fu)用(yong)(yong)/解復(fu)(fu)(fu)用(yong)(yong)器,將(jiang)諸(zhu)多的(de)主機(ji)(ji)進程數據(ju)復(fu)(fu)(fu)用(yong)(yong)/解復(fu)(fu)(fu)用(yong)(yong)到IP層。可(ke)以看出(chu),不管從哪(na)個(ge)(ge)(ge)角度,TCP都作為(wei)一(yi)(yi)個(ge)(ge)(ge)接口(kou)(kou)(kou)(kou)存(cun)在,作為(wei)網絡(luo)(luo)協(xie)(xie)議(yi),它(ta)(ta)和(he)(he)對(dui)端的(de)TCP接口(kou)(kou)(kou)(kou),實現TCP的(de)控制(zhi)邏(luo)輯,作為(wei)多路(lu)(lu)復(fu)(fu)(fu)用(yong)(yong)/解復(fu)(fu)(fu)用(yong)(yong)器,它(ta)(ta)和(he)(he)下(xia)層IP 協(xie)(xie)議(yi)接口(kou)(kou)(kou)(kou),實現協(xie)(xie)議(yi)棧的(de)功能,而這正是(shi)分層網絡(luo)(luo)協(xie)(xie)議(yi)模型的(de)基本定義(兩類接口(kou)(kou)(kou)(kou),一(yi)(yi)類和(he)(he)下(xia)層接口(kou)(kou)(kou)(kou),另(ling)一(yi)(yi)類和(he)(he)對(dui)等層接口(kou)(kou)(kou)(kou))。
我們習(xi)慣于(yu)將TCP作為協(xie)議(yi)(yi)(yi)棧的(de)(de)最頂端,而(er)不把應(ying)用(yong)(yong)層協(xie)議(yi)(yi)(yi)當成(cheng)協(xie)議(yi)(yi)(yi)棧的(de)(de)一部分,這部分是因為應(ying)用(yong)(yong)層被(bei)TCP/UDP解復用(yong)(yong)了之(zhi)后,呈現出了一種太復雜的(de)(de)局(ju)面,應(ying)用(yong)(yong)層協(xie)議(yi)(yi)(yi)用(yong)(yong)一種不同截然(ran)不同的(de)(de)方式被(bei)解釋(shi),應(ying)用(yong)(yong)層協(xie)議(yi)(yi)(yi)習(xi)慣于(yu)用(yong)(yong)類似ASN.1標準來封裝,這正體(ti)現了TCP協(xie)議(yi)(yi)(yi)作為多(duo)路復用(yong)(yong)/解復用(yong)(yong)器的(de)(de)重要性,由于(yu)直接(jie)(jie)和應(ying)用(yong)(yong)接(jie)(jie)口(kou),它可以(yi)很容易直接(jie)(jie)被(bei)應(ying)用(yong)(yong)控制,實現不同的(de)(de)傳輸控制策略,這也(ye)是TCP被(bei)設計到離應(ying)用(yong)(yong)不太遠的(de)(de)地方的(de)(de)原(yuan)因之(zhi)一。
總(zong)之,TCP要點有(you)四(si),一(yi)曰(yue)有(you)連接,二曰(yue)可(ke)靠傳輸,三曰(yue)數據按照(zhao)到達(da),四(si)曰(yue)端(duan)到端(duan)流量控制。注意,TCP被設計時只保(bao)證(zheng)這(zhe)四(si)點,此(ci)(ci)時它雖然也有(you)些問題(ti),然而(er)(er)很(hen)簡(jian)單(dan),然而(er)(er)更大的(de)問題(ti)很(hen)快呈現出(chu)來(lai),使(shi)之不(bu)得不(bu)考(kao)慮和(he)IP網絡相(xiang)關的(de)東西,比(bi)如公(gong)平(ping)性,效率,因此(ci)(ci)增加了(le)擁塞控制,這(zhe)樣TCP就成了(le)現在這(zhe)個(ge)樣子。
3.2.有連接,可靠傳輸,數據按序到達的(de)TCP
IP 協議是(shi)沒(mei)有(you)方向的(de),數(shu)據報傳輸(shu)能到達(da)(da)對端(duan)(duan)(duan)全靠路(lu)(lu)(lu)(lu)由(you),因此它是(shi)一(yi)跳一(yi)跳地(di)到達(da)(da)對端(duan)(duan)(duan)的(de),只要有(you)一(yi)跳沒(mei)有(you)到達(da)(da)對端(duan)(duan)(duan)的(de)路(lu)(lu)(lu)(lu)由(you),那么數(shu)據傳輸(shu)將失(shi)敗,其(qi)實路(lu)(lu)(lu)(lu)由(you)也(ye)是(shi)互聯網的(de)核心之一(yi),實際上IP層提供的(de)核心基(ji)本功(gong)能有(you)兩點,第(di)一(yi)點是(shi)地(di)址管(guan)理,第(di)二點就是(shi)路(lu)(lu)(lu)(lu)由(you)選路(lu)(lu)(lu)(lu)。TCP利用(yong)了(le)IP路(lu)(lu)(lu)(lu)由(you)這個簡(jian)單的(de)功(gong)能,因此TCP不必(bi)考(kao)慮選路(lu)(lu)(lu)(lu),這又一(yi)個它被設計成(cheng)端(duan)(duan)(duan)到端(duan)(duan)(duan)協議的(de)原因。
既然IP已經能盡力(li)讓單獨(du)的數據報到達對端(duan),那么TCP就可以在(zai)這種(zhong)盡力(li)而為的網(wang)絡上實現其它的更加(jia)(jia)嚴格的控制(zhi)功(gong)能。TCP給無連接的IP網(wang)絡通(tong)信增加(jia)(jia)了(le)(le)連接性,確(que)認(ren)了(le)(le)已經發送出(chu)去的數據的狀態(tai),并且保(bao)證了(le)(le)數據的順序。
3.2.1.有連(lian)接
這是(shi)TCP的(de)(de)(de)基本,因(yin)為(wei)后續的(de)(de)(de)傳(chuan)輸的(de)(de)(de)可(ke)靠性以及數(shu)(shu)據(ju)順序(xu)性都依賴于一條連接,這是(shi)最簡(jian)單的(de)(de)(de)實現(xian)方式,因(yin)此TCP被設計成一種基于流(liu)的(de)(de)(de)協議,既然TCP需要事先建立連接,之(zhi)后傳(chuan)輸多少數(shu)(shu)據(ju)就(jiu)無所謂了,只要是(shi)同一連接的(de)(de)(de)數(shu)(shu)據(ju)能識別出(chu)來即可(ke)。
疑難雜癥1:3次握手(shou)和4次揮手(shou)
TCP 使用(yong)3次握(wo)(wo)(wo)手建立一條連接,該握(wo)(wo)(wo)手初(chu)始(shi)化(hua)了(le)傳輸可靠性以及數據順序性必要的(de)(de)信息(xi),這些信息(xi)包括兩(liang)個方(fang)向的(de)(de)初(chu)始(shi)序列(lie)號(hao)(hao),確認號(hao)(hao)由初(chu)始(shi)序列(lie)號(hao)(hao)生成,使用(yong)3次握(wo)(wo)(wo)手是(shi)因為3次握(wo)(wo)(wo)手已(yi)經準備好了(le)傳輸可靠性以及數據順序性所必要的(de)(de)信息(xi),該握(wo)(wo)(wo)手的(de)(de)第3次實際上并不(bu)是(shi)需要單獨傳輸的(de)(de),完全可以和(he)數據一起(qi)傳輸。
TCP使用(yong)4次(ci)揮(hui)手拆除(chu)一(yi)(yi)條連(lian)接,為何需要(yao)4次(ci)呢(ni)?因為TCP是一(yi)(yi)個(ge)(ge)全雙工協議,必須單獨拆除(chu)每一(yi)(yi)條信道。注意,4次(ci)揮(hui)手和3次(ci)握(wo)手的(de)(de)意義(yi)是不同的(de)(de),很多(duo)人(ren)都(dou)(dou)會問(wen)為何建(jian)立連(lian)接是3次(ci)握(wo)手,而(er)拆除(chu)連(lian)接是4次(ci)揮(hui)手。3次(ci)握(wo)手的(de)(de)目的(de)(de)很簡單,就(jiu)是分配資(zi)源,初始化序列(lie)(lie)(lie)號(hao),這時還不涉及數據(ju)(ju)傳(chuan)(chuan)輸,3次(ci)就(jiu)足(zu)夠做到這個(ge)(ge)了(le),而(er) 4次(ci)揮(hui)手的(de)(de)目的(de)(de)是終止數據(ju)(ju)傳(chuan)(chuan)輸,并回收資(zi)源,此(ci)時兩(liang)(liang)個(ge)(ge)端點兩(liang)(liang)個(ge)(ge)方(fang)向的(de)(de)序列(lie)(lie)(lie)號(hao)已經沒有(you)了(le)任(ren)何關系(xi),必須等待兩(liang)(liang)方(fang)向都(dou)(dou)沒有(you)數據(ju)(ju)傳(chuan)(chuan)輸時才(cai)能拆除(chu)虛鏈路,不像(xiang)初始化時那么(me)簡單,發現(xian)SYN標志就(jiu)初始化一(yi)(yi)個(ge)(ge)序列(lie)(lie)(lie)號(hao)并確(que)認(ren)SYN的(de)(de)序列(lie)(lie)(lie)號(hao)。因此(ci)必須單獨分別在一(yi)(yi)個(ge)(ge)方(fang)向上終止該方(fang)向的(de)(de)數據(ju)(ju)傳(chuan)(chuan)輸。
疑難雜癥2:TIME_WAIT狀(zhuang)態
為何要有這(zhe)個狀態(tai),原因很簡(jian)單,那就是每次建立連接的時候序(xu)列號(hao)都是隨機產生的,并且這(zhe)個序(xu)列號(hao)是32位的,會(hui)回繞(rao)。現在我(wo)來(lai)解(jie)釋這(zhe)和TIME_WAIT有什么關系。
任何(he)的(de)(de)TCP分段都(dou)要在(zai)盡力而(er)為的(de)(de)IP網絡上(shang)傳(chuan)輸,中間的(de)(de)路由器(qi)可能會隨意的(de)(de)緩存任何(he)的(de)(de)IP數(shu)據報(bao)(bao)(bao),它并(bing)不管這個IP數(shu)據報(bao)(bao)(bao)上(shang)被承載的(de)(de)是(shi)什么數(shu)據,然而(er)根據經驗和互聯網的(de)(de)大(da)小,一個IP數(shu)據報(bao)(bao)(bao)最(zui)多存活MSL(這是(shi)根據地球表面積(ji),電(dian)磁波在(zai)各種介質中的(de)(de)傳(chuan)輸速率(lv)以及(ji)IP協(xie)議的(de)(de)TTL等綜合推算出來的(de)(de),如(ru)果在(zai)火(huo)星上(shang),這個MSL會大(da)得多...)。
現在(zai)我們考慮終止連(lian)接時的被動(dong)方(fang)發送(song)了一個(ge)FIN,然后(hou)主動(dong)方(fang)回(hui)復了一個(ge)ACK,然而這(zhe)個(ge)ACK可(ke)能(neng)會丟失,這(zhe)會造(zao)成被動(dong)方(fang)重(zhong)發FIN,這(zhe)個(ge)FIN可(ke)能(neng)會在(zai)互聯網上存(cun)活(huo)MSL。
如(ru)果沒有TIME_WAIT的(de)(de)話,假(jia)設連接(jie)1已經(jing)斷開,然(ran)而其被動方最(zui)后重(zhong)發的(de)(de)那個FIN(或者FIN之前發送的(de)(de)任何TCP分段(duan))還(huan)在網絡上,然(ran)而連接(jie)2 重(zhong)用了連接(jie)1的(de)(de)所有的(de)(de)5元素(su)(源IP,目的(de)(de)IP,TCP,源端口,目的(de)(de)端口),剛(gang)剛(gang)將建(jian)立好(hao)連接(jie),連接(jie)1遲到的(de)(de)FIN到達了,這個FIN將以比較低但是確實可能的(de)(de)概率終止掉連接(jie)2.
為何說是概率比較低呢(ni)?這涉及到一(yi)個匹(pi)配問題,遲(chi)到的(de)FIN分段的(de)序列(lie)號(hao)必須落在(zai)連(lian)接2的(de)一(yi)方的(de)期望序列(lie)號(hao)范圍之(zhi)內。雖然(ran)這種(zhong)巧合很少發生,但確實會(hui)發生,畢(bi)竟(jing)初始序列(lie)號(hao)是隨機產生了(le)。因(yin)此終止(zhi)連(lian)接的(de)主動方必須在(zai)接受了(le)被(bei)動方且(qie)回復了(le)ACK之(zhi)后等待2*MSL時間才能進入CLOSE狀態,之(zhi)所(suo)以(yi)(yi)乘(cheng)以(yi)(yi)2是因(yin)為這是保(bao)守的(de)算法(fa),最壞情況下(xia),針對(dui)被(bei)動方的(de)ACK在(zai)以(yi)(yi)最長(chang)路(lu)線(經歷一(yi)個MSL)經過互聯網馬上到達被(bei)動方時丟失。
為了應(ying)對這個(ge)問(wen)題,RFC793對初始序列號(hao)的(de)(de)生成有個(ge)建議(yi),那(nei)(nei)就是(shi)(shi)設(she)定一個(ge)基(ji)準(zhun),在(zai)這個(ge)基(ji)準(zhun)之上搞隨(sui)機(ji),這個(ge)基(ji)準(zhun)就是(shi)(shi)時(shi)(shi)間(jian),我們知道時(shi)(shi)間(jian)是(shi)(shi)單調(diao)遞增的(de)(de)。然(ran)而這仍然(ran)有問(wen)題,那(nei)(nei)就是(shi)(shi)回繞問(wen)題,如果發生回繞,那(nei)(nei)么新的(de)(de)序列號(hao)將會(hui)落到一個(ge)很低的(de)(de)值。因(yin)此的(de)(de)辦法就是(shi)(shi)避開“重疊(die)”,其含義(yi)就是(shi)(shi)基(ji)準(zhun)之上的(de)(de)隨(sui)機(ji)要設(she)定一個(ge)范圍。
要知道(dao),很多(duo)人很不喜歡看到服務器上出現大量(liang)的(de)(de)(de)(de)TIME_WAIT狀態的(de)(de)(de)(de)連接,因此他們(men)將TIME_WAIT的(de)(de)(de)(de)值設(she)置的(de)(de)(de)(de)很低(di),這雖(sui)然在大多(duo)數情況下(xia)可行(xing),然而確實也是(shi)一(yi)種冒險行(xing)為。的(de)(de)(de)(de)方式就(jiu)是(shi),不要重用一(yi)個(ge)連接。
疑難雜癥3:重用(yong)一個連接和重用(yong)一個套接字
這(zhe)是根(gen)本不同(tong)的(de)(de),單獨重用(yong)一(yi)(yi)(yi)(yi)個(ge)(ge)套接(jie)(jie)字(zi)(zi)一(yi)(yi)(yi)(yi)般不會(hui)有(you)任(ren)何問題,因為TCP是基于(yu)(yu)連(lian)接(jie)(jie)的(de)(de)。比如在服(fu)務器(qi)端(duan)(duan)出現了(le)一(yi)(yi)(yi)(yi)個(ge)(ge)TIME_WAIT連(lian)接(jie)(jie),那么該連(lian)接(jie)(jie)標識了(le)一(yi)(yi)(yi)(yi)個(ge)(ge)五(wu)元(yuan)素,只要客戶端(duan)(duan)不使用(yong)相同(tong)的(de)(de)源端(duan)(duan)口,連(lian)接(jie)(jie)服(fu)務器(qi)是沒有(you)問題的(de)(de),因為遲到的(de)(de)FIN永遠不會(hui)到達這(zhe)個(ge)(ge)連(lian)接(jie)(jie)。記(ji)住,一(yi)(yi)(yi)(yi)個(ge)(ge)五(wu)元(yuan)素標識了(le)一(yi)(yi)(yi)(yi)個(ge)(ge)連(lian)接(jie)(jie),而(er)不是一(yi)(yi)(yi)(yi)個(ge)(ge)套接(jie)(jie)字(zi)(zi)(當然,對于(yu)(yu)BSD套接(jie)(jie)字(zi)(zi)而(er)言(yan),服(fu)務端(duan)(duan)的(de)(de)accept套接(jie)(jie)字(zi)(zi)確實(shi)標識了(le)一(yi)(yi)(yi)(yi)個(ge)(ge)連(lian)接(jie)(jie))。
3.2.2.傳輸可靠性
基(ji)本(ben)上傳輸(shu)可(ke)靠性是(shi)(shi)(shi)靠確(que)認(ren)(ren)號實現(xian)的(de)(de),也就是(shi)(shi)(shi)說,每發送一(yi)(yi)(yi)個(ge)(ge)分段,接(jie)下(xia)來(lai)接(jie)收端必然要發送一(yi)(yi)(yi)個(ge)(ge)確(que)認(ren)(ren),發送端收到確(que)認(ren)(ren)后才可(ke)以發送下(xia)一(yi)(yi)(yi)個(ge)(ge)字(zi)節。這個(ge)(ge)原則(ze)(ze)最簡單不過了(le),教科(ke)書上的(de)(de)“停止-等待(dai)”協議就是(shi)(shi)(shi)這個(ge)(ge)原則(ze)(ze)的(de)(de)字(zi)節版本(ben),只是(shi)(shi)(shi)TCP使用了(le)滑動(dong)窗口機(ji)制使得(de)每次不一(yi)(yi)(yi)定發送一(yi)(yi)(yi)個(ge)(ge)字(zi)節,但是(shi)(shi)(shi)這是(shi)(shi)(shi)后話,本(ben)節僅僅談一(yi)(yi)(yi)下(xia)確(que)認(ren)(ren)的(de)(de)超時機(ji)制。
怎么知道數據到(dao)達對(dui)端(duan)呢?那就是對(dui)端(duan)發送一個確(que)認,但是如(ru)果(guo)一直(zhi)收不(bu)到(dao)對(dui)端(duan)的確(que)認,發送端(duan)等(deng)(deng)(deng)多久呢?如(ru)果(guo)一直(zhi)等(deng)(deng)(deng)下去,那么將無(wu)法發現數據的丟失,協(xie)議將不(bu)可用,如(ru)果(guo)等(deng)(deng)(deng)待(dai)時(shi)(shi)間(jian)過短,可能確(que)認還(huan)在路上(shang),因(yin)此等(deng)(deng)(deng)待(dai)時(shi)(shi)間(jian)是個問題(ti)(ti),另外如(ru)何(he)去管(guan)理這個超(chao)時(shi)(shi)時(shi)(shi)間(jian)也是一個問題(ti)(ti)。
疑難雜癥4:超時時間(jian)的(de)計算(suan)
絕(jue)對不(bu)(bu)能隨(sui)意(yi)去揣測超時(shi)的(de)(de)(de)時(shi)間(jian),而應該(gai)給出一(yi)(yi)(yi)個(ge)精(jing)確的(de)(de)(de)算法去計算。毫無(wu)(wu)疑問,一(yi)(yi)(yi)個(ge)TCP分段(duan)(duan)的(de)(de)(de)回復(fu)到達的(de)(de)(de)時(shi)間(jian)就(jiu)是一(yi)(yi)(yi)個(ge)數據報往(wang)返的(de)(de)(de)時(shi)間(jian),因此標準(zhun)定義了一(yi)(yi)(yi)個(ge)新的(de)(de)(de)名詞RTT,代表一(yi)(yi)(yi)個(ge)TCP分段(duan)(duan)的(de)(de)(de)往(wang)返時(shi)間(jian)。然(ran)而我們(men)知道,IP網絡是盡力而為的(de)(de)(de),并且路(lu)由(you)是動態(tai)的(de)(de)(de),且路(lu)由(you)器會毫無(wu)(wu)先兆的(de)(de)(de)緩存或者丟棄任(ren)何的(de)(de)(de)數據報,因此這個(ge)RTT是需(xu)要(yao)動態(tai)測量的(de)(de)(de),也就(jiu)是說起碼每(mei)隔(ge)一(yi)(yi)(yi)段(duan)(duan)時(shi)間(jian)就(jiu)要(yao)測量一(yi)(yi)(yi)次,如果(guo)每(mei)次都一(yi)(yi)(yi)樣,萬事大吉,然(ran)而世界并非如你所(suo)愿,因此我們(men)需(xu)要(yao)找到的(de)(de)(de)恰(qia)恰(qia)的(de)(de)(de)一(yi)(yi)(yi)個(ge)“平均值”,而不(bu)(bu)是一(yi)(yi)(yi)個(ge)準(zhun)確值。
這個平均(jun)(jun)值(zhi)如(ru)果(guo)(guo)僅(jin)僅(jin)直(zhi)接通(tong)過(guo)(guo)計算(suan)(suan)多次測量值(zhi)取算(suan)(suan)術(shu)平均(jun)(jun),那是不恰(qia)當(dang)的(de)(de)(de),因為對于(yu)數(shu)據傳(chuan)(chuan)輸延時,我們必須考慮的(de)(de)(de)路徑(jing)延遲(chi)(chi)的(de)(de)(de)瞬間抖動,否則(ze)如(ru)果(guo)(guo)兩次測量值(zhi)分(fen)別(bie)為2和98,那么超時值(zhi)將是50,這個值(zhi)對于(yu)2而(er)言(yan),太大了(le)(le),結果(guo)(guo)造(zao)成(cheng)了(le)(le)數(shu)據的(de)(de)(de)延遲(chi)(chi)過(guo)(guo)大(本(ben)該重傳(chuan)(chuan)的(de)(de)(de)等待了(le)(le)好久才重傳(chuan)(chuan)),然(ran)而(er)對于(yu)98而(er)言(yan),太小了(le)(le),結果(guo)(guo)造(zao)成(cheng)了(le)(le)過(guo)(guo)度重傳(chuan)(chuan)(路途遙遠,本(ben)該很(hen)慢,結果(guo)(guo)大量重傳(chuan)(chuan)已(yi)經正確(que)確(que)認但(dan)是遲(chi)(chi)到的(de)(de)(de)TCP分(fen)段)。
因此,除了考(kao)慮每兩次(ci)測量值(zhi)的(de)偏(pian)差之(zhi)外,其變(bian)(bian)(bian)化率(lv)也應該考(kao)慮在內,如(ru)(ru)果(guo)變(bian)(bian)(bian)化率(lv)過大(da),則(ze)通過以(yi)變(bian)(bian)(bian)化率(lv)為自(zi)變(bian)(bian)(bian)量的(de)函數為主計算RTT(如(ru)(ru)果(guo)陡然增大(da),則(ze)取值(zhi)為比較大(da)的(de)正數,如(ru)(ru)果(guo)陡然減小,則(ze)取值(zhi)為比較小的(de)負數,然后(hou)和(he)平均值(zhi)加權求和(he)),反之(zhi)如(ru)(ru)果(guo)變(bian)(bian)(bian)化率(lv)很(hen)小,則(ze)取測量平均值(zhi)。這是不言(yan)而喻(yu)的(de),這個算法至今仍然工作的(de)很(hen)好。
疑(yi)難雜癥5:超時計(ji)時器的管理-每連接單(dan)一計(ji)時器
很顯然,對每(mei)一(yi)(yi)個(ge)TCP分(fen)段都生成(cheng)一(yi)(yi)個(ge)計(ji)(ji)時(shi)器(qi)(qi)是最(zui)直接的(de)(de)(de)方式,每(mei)個(ge)計(ji)(ji)時(shi)器(qi)(qi)在RTT時(shi)間后到(dao)期,如(ru)果(guo)沒有(you)收到(dao)確認(ren),則重傳。然而(er)這(zhe)只是理(li)(li)論上的(de)(de)(de)合理(li)(li),對于大多(duo)數操作系(xi)統而(er)言,這(zhe)將(jiang)帶來巨大的(de)(de)(de)內存(cun)開銷(xiao)和調度開銷(xiao),因此采取每(mei)一(yi)(yi)個(ge)TCP連接單一(yi)(yi)計(ji)(ji)時(shi)器(qi)(qi)的(de)(de)(de)設計(ji)(ji)則成(cheng)了一(yi)(yi)個(ge)默認(ren)的(de)(de)(de)選擇。可是單一(yi)(yi)的(de)(de)(de)計(ji)(ji)時(shi)器(qi)(qi)怎么管理(li)(li)如(ru)此多(duo)的(de)(de)(de)發出去的(de)(de)(de)TCP分(fen)段呢?又該如(ru)何來設計(ji)(ji)單一(yi)(yi)的(de)(de)(de)計(ji)(ji)時(shi)器(qi)(qi)呢。
設計單一(yi)計時器有(you)兩個(ge)原則:1.每一(yi)個(ge)報(bao)文在長期收(shou)不(bu)到確(que)認都(dou)必須可以超時;2.這(zhe)個(ge)長期收(shou)不(bu)到中(zhong)長期不(bu)能和(he)測量(liang)的RTT相(xiang)隔太遠。因此(ci)RFC2988定義(yi)一(yi)套很簡單的原則:
a.發送TCP分段(duan)時(shi),如果還沒有重傳定(ding)時(shi)器開(kai)啟,那么開(kai)啟它(ta)。
b.發送TCP分段(duan)時,如果已經有重傳定時器開啟(qi),不再(zai)開啟(qi)它(ta)。
c.收(shou)到一個(ge)非冗余ACK時,如果有數(shu)據在傳輸中,重新(xin)開啟重傳定(ding)時器。
d.收到一個非冗余ACK時,如果沒有數據在(zai)傳輸(shu)中,則關閉(bi)重傳定時器。
我們看看這(zhe)4條規(gui)則(ze)(ze)(ze)是(shi)(shi)如何(he)(he)做到(dao)以上兩點的(de),根據(ju)(ju)a和c(在(zai)c中,注意(yi)到(dao)ACK是(shi)(shi)非冗(rong)余(yu)的(de)),任何(he)(he)TCP分段(duan)只要(yao)不(bu)(bu)被(bei)確(que)(que)認,超(chao)(chao)時(shi)(shi)(shi)(shi)定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi)總會(hui)超(chao)(chao)時(shi)(shi)(shi)(shi)的(de)。然而為何(he)(he)需要(yao)c呢?只有(you)規(gui)則(ze)(ze)(ze)a存(cun)在(zai)的(de)話,也可以做到(dao)原則(ze)(ze)(ze)1。實際上確(que)(que)實是(shi)(shi)這(zhe)樣(yang)的(de),但是(shi)(shi)為了(le)不(bu)(bu)會(hui)出(chu)現過早重(zhong)(zhong)傳(chuan),才添加了(le)規(gui)則(ze)(ze)(ze)c,如果沒(mei)有(you)規(gui)則(ze)(ze)(ze)c,那么萬一在(zai)重(zhong)(zhong)傳(chuan)定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi)到(dao)期(qi)前,發(fa)送了(le)一些(xie)數(shu)據(ju)(ju),這(zhe)樣(yang)在(zai)定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi)到(dao)期(qi)后,除了(le)很早發(fa)送的(de)數(shu)據(ju)(ju)能收到(dao)ACK外(wai),其它稍晚些(xie)發(fa)送的(de)數(shu)據(ju)(ju)的(de)ACK都將不(bu)(bu)會(hui)到(dao)來,因此這(zhe)些(xie)數(shu)據(ju)(ju)都將被(bei)重(zhong)(zhong)傳(chuan)。有(you)了(le)規(gui)則(ze)(ze)(ze)c之后,只要(yao)有(you)分段(duan)ACK到(dao)來,則(ze)(ze)(ze)重(zhong)(zhong)置重(zhong)(zhong)傳(chuan)定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi),這(zhe)很合理,因此大(da)多(duo)數(shu)正常情況下,從數(shu)據(ju)(ju)的(de)發(fa)出(chu)到(dao)ACK的(de)到(dao)來這(zhe)段(duan)時(shi)(shi)(shi)(shi)間(jian)以及(ji)計算得到(dao)的(de)RTT以及(ji)重(zhong)(zhong)傳(chuan)定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi)超(chao)(chao)時(shi)(shi)(shi)(shi)的(de)時(shi)(shi)(shi)(shi)間(jian)這(zhe)三者相差并不(bu)(bu)大(da),一個ACK到(dao)來后重(zhong)(zhong)置定(ding)時(shi)(shi)(shi)(shi)器(qi)(qi)可以保護后發(fa)的(de)數(shu)據(ju)(ju)不(bu)(bu)被(bei)過早重(zhong)(zhong)傳(chuan)。
這里(li)面(mian)還有(you)一(yi)(yi)些細節需(xu)要說(shuo)明。一(yi)(yi)個(ge)(ge)(ge)ACK到(dao)來了(le),說(shuo)明后續的(de)(de)(de)(de)ACK很可(ke)能會(hui)(hui)依次到(dao)來,也就是(shi)說(shuo)丟(diu)(diu)失(shi)的(de)(de)(de)(de)可(ke)能性并不大,另外,即(ji)使真的(de)(de)(de)(de)有(you)后發(fa)(fa)(fa)的(de)(de)(de)(de)TCP分段丟(diu)(diu)失(shi)現象發(fa)(fa)(fa)生,也會(hui)(hui)在最(zui)多(duo)2倍定(ding)時(shi)(shi)器(qi)超時(shi)(shi)時(shi)(shi)間(jian)的(de)(de)(de)(de)范圍內被重(zhong)傳(chuan)(chuan)(假設(she)(she)該報文(wen)是(shi)第(di)一(yi)(yi)個(ge)(ge)(ge)報文(wen)發(fa)(fa)(fa)出啟(qi)動定(ding)時(shi)(shi)器(qi)之(zhi)后馬上發(fa)(fa)(fa)出的(de)(de)(de)(de),丟(diu)(diu)失(shi)了(le),第(di)一(yi)(yi)個(ge)(ge)(ge)報文(wen)的(de)(de)(de)(de)ACK到(dao)來后又重(zhong)啟(qi)了(le)定(ding)時(shi)(shi)器(qi),又經過了(le)一(yi)(yi)個(ge)(ge)(ge)超時(shi)(shi)時(shi)(shi)間(jian)才(cai)會(hui)(hui)被重(zhong)傳(chuan)(chuan))。雖(sui)然這里(li)還沒有(you)涉及擁塞控制,但(dan)是(shi)可(ke)見網絡擁塞會(hui)(hui)引起(qi)丟(diu)(diu)包,丟(diu)(diu)包會(hui)(hui)引起(qi)重(zhong)傳(chuan)(chuan),過度重(zhong)傳(chuan)(chuan)反(fan)過來加重(zhong)網絡擁塞,設(she)(she)置規則c的(de)(de)(de)(de)結果可(ke)以緩解過多(duo)的(de)(de)(de)(de)重(zhong)傳(chuan)(chuan),畢竟將啟(qi)動定(ding)時(shi)(shi)器(qi)之(zhi)后發(fa)(fa)(fa)送(song)的(de)(de)(de)(de)數(shu)據的(de)(de)(de)(de)重(zhong)傳(chuan)(chuan)超時(shi)(shi)時(shi)(shi)間(jian)拉長(chang)(chang)了(le)最(zui)多(duo)一(yi)(yi)倍左右。最(zui)多(duo)一(yi)(yi)倍左右的(de)(de)(de)(de)超時(shi)(shi)偏(pian)差做到(dao)了(le)原則2,即(ji)“這個(ge)(ge)(ge)長(chang)(chang)期收不到(dao)中長(chang)(chang)期不能和測量的(de)(de)(de)(de)RTT相隔太遠(yuan)”。
還(huan)有一(yi)點(dian),如果是一(yi)個發(fa)(fa)送序列的最后(hou)(hou)一(yi)個分段(duan)丟失(shi)了,后(hou)(hou)面(mian)就不會(hui)收到冗余ACK,這樣(yang)就只(zhi)能等到超時(shi)(shi)(shi)了,并且超時(shi)(shi)(shi)時(shi)(shi)(shi)間(jian)幾乎是肯定會(hui)比定時(shi)(shi)(shi)器超時(shi)(shi)(shi)時(shi)(shi)(shi)間(jian)更(geng)長。如果這個分段(duan)是在(zai)發(fa)(fa)送序列的靠后(hou)(hou)的時(shi)(shi)(shi)間(jian)發(fa)(fa)送的且和前面(mian)的發(fa)(fa)送時(shi)(shi)(shi)間(jian)相隔(ge)時(shi)(shi)(shi)間(jian)較(jiao)遠(yuan),則其超時(shi)(shi)(shi)時(shi)(shi)(shi)間(jian)不會(hui)很大,反之就會(hui)比較(jiao)大。
疑難雜癥6:何時測(ce)量RTT
目前很多TCP實現了時間(jian)戳,這樣就(jiu)方(fang)便多了,發(fa)(fa)送端再(zai)也(ye)不需(xu)要(yao)保存發(fa)(fa)送分段的時間(jian)了,只需(xu)要(yao)將其放入協議頭的時間(jian)戳字段,然后(hou)接收端將其回顯(xian)在(zai)ACK即(ji)可(ke),然后(hou)發(fa)(fa)送端收到ACK后(hou),取出時間(jian)戳,和當前時間(jian)做算(suan)術(shu)差,即(ji)可(ke)完(wan)成一次RTT的測(ce)量。
3.2.3.數(shu)據順序(xu)性
基本上傳輸可靠性(xing)是靠序列號(hao)實(shi)現的。
疑難雜癥7:確認號和(he)超時重(zhong)傳
確認(ren)號是一(yi)個很詭異(yi)的(de)(de)東西,因(yin)為(wei)TCP的(de)(de)發送端(duan)對于發送出(chu)去(qu)的(de)(de)一(yi)個數據(ju)序列,它(ta)只要收(shou)到一(yi)個確認(ren)號就認(ren)為(wei)確認(ren)號前面的(de)(de)數據(ju)都被收(shou)到了,即使前面的(de)(de)某個確認(ren)號丟失(shi)了,也就是說,發送端(duan)只認(ren)最后一(yi)個確認(ren)號。這(zhe)是合理(li)的(de)(de),因(yin)為(wei)確認(ren)號是接收(shou)端(duan)發出(chu)的(de)(de),接收(shou)端(duan)只確認(ren)按(an)序到達的(de)(de)最后一(yi)個TCP分段。
另外,發送端(duan)重(zhong)(zhong)(zhong)(zhong)發了(le)(le)一個(ge)TCP報(bao)文并且接(jie)收(shou)到該TCP分段的(de)(de)(de)(de)確認(ren)號,并不能說(shuo)明這個(ge)重(zhong)(zhong)(zhong)(zhong)發的(de)(de)(de)(de)報(bao)文被(bei)(bei)接(jie)收(shou)了(le)(le),也可能是(shi)數據(ju)早(zao)就被(bei)(bei)接(jie)收(shou)了(le)(le),只是(shi)由于其ACK丟失或者其ACK延遲(chi)到達導致了(le)(le)超時。值得(de)說(shuo)明的(de)(de)(de)(de)是(shi),接(jie)收(shou)端(duan)會(hui)丟棄任何(he)重(zhong)(zhong)(zhong)(zhong)復的(de)(de)(de)(de)數據(ju),即使丟棄了(le)(le)重(zhong)(zhong)(zhong)(zhong)復的(de)(de)(de)(de)數據(ju),其ACK還是(shi)會(hui)照發不誤(wu)的(de)(de)(de)(de)。
標準的(de)(de)早期TCP實現為(wei)(wei),只要一個(ge)TCP分(fen)(fen)段(duan)丟(diu)(diu)(diu)(diu)失(shi),即使(shi)后(hou)面的(de)(de)TCP分(fen)(fen)段(duan)都被(bei)完整收(shou)(shou)到(dao),發送端還是會重傳(chuan)從(cong)丟(diu)(diu)(diu)(diu)失(shi)分(fen)(fen)段(duan)開(kai)始(shi)的(de)(de)所有報(bao)文(wen),這(zhe)就(jiu)會導致一個(ge)問題,那就(jiu)是重傳(chuan)風暴,一個(ge)分(fen)(fen)段(duan)丟(diu)(diu)(diu)(diu)失(shi),引起大(da)量(liang)的(de)(de)重傳(chuan)。這(zhe)種風暴實則不必要的(de)(de),因為(wei)(wei)大(da)多數的(de)(de)TCP實現中,接收(shou)(shou)端已經緩(huan)存了亂序(xu)的(de)(de)分(fen)(fen)段(duan),這(zhe)些被(bei)重傳(chuan)的(de)(de)丟(diu)(diu)(diu)(diu)失(shi)分(fen)(fen)段(duan)之后(hou)的(de)(de)分(fen)(fen)段(duan)到(dao)達(da)接收(shou)(shou)端之后(hou),很大(da)的(de)(de)可能(neng)性(xing)是被(bei)丟(diu)(diu)(diu)(diu)棄。關于這(zhe)一點在(zai)擁塞控制(zhi)被(bei)引入(ru)之后(hou)還會提及(ji)(問題先述為(wei)(wei)快:本來報(bao)文(wen)丟(diu)(diu)(diu)(diu)失(shi)導致超時就(jiu)說明網絡(luo)很可能(neng)已然擁塞,重傳(chuan)風暴只能(neng)加(jia)重其(qi)擁塞程度)。
疑難雜(za)癥8:亂序數(shu)據緩存(cun)以及選(xuan)擇確認
TCP 是(shi)(shi)保證(zheng)數據(ju)順序(xu)(xu)的(de)(de)(de),但是(shi)(shi)并不(bu)意味著它總是(shi)(shi)會(hui)丟(diu)棄亂(luan)序(xu)(xu)的(de)(de)(de)TCP分(fen)(fen)(fen)段(duan)(duan),具體(ti)會(hui)不(bu)會(hui)丟(diu)棄是(shi)(shi)和具體(ti)實(shi)現(xian)(xian)相關的(de)(de)(de),RFC建議(yi)如果內存允許,還是(shi)(shi)要(yao)緩(huan)(huan)存這些亂(luan)序(xu)(xu)到(dao)來的(de)(de)(de)分(fen)(fen)(fen)段(duan)(duan),然后(hou)實(shi)現(xian)(xian)一(yi)種機制等到(dao)可以拼接成一(yi)個按序(xu)(xu)序(xu)(xu)列的(de)(de)(de)時候(hou)將(jiang)緩(huan)(huan)存的(de)(de)(de)分(fen)(fen)(fen)段(duan)(duan)拼接,這就類似于IP協(xie)議(yi)中的(de)(de)(de)分(fen)(fen)(fen)片一(yi)樣,但是(shi)(shi)由于IP數據(ju)報(bao)是(shi)(shi)不(bu)確(que)認的(de)(de)(de),因(yin)此(ci)IP協(xie)議(yi)的(de)(de)(de)實(shi)現(xian)(xian)必須緩(huan)(huan)存收(shou)到(dao)的(de)(de)(de)任何(he)分(fen)(fen)(fen)片而(er)不(bu)能將(jiang)其丟(diu)棄,因(yin)為(wei)丟(diu)棄了一(yi)個IP分(fen)(fen)(fen)片,它就再(zai)也不(bu)會(hui)到(dao)來了。
現在,TCP實現了一種稱為選擇確認的方式(shi),接(jie)收端會顯式(shi)告訴發送(song)端需(xu)要重傳哪些(xie)分段而(er)不需(xu)要重傳哪些(xie)分段。這無疑避(bi)免了重傳風暴。
疑難雜(za)癥9:TCP序列(lie)號的回繞的問(wen)題(ti)
TCP 的(de)序列(lie)(lie)號(hao)(hao)回繞會(hui)(hui)引(yin)起很多(duo)的(de)問(wen)(wen)題,比如(ru)序列(lie)(lie)號(hao)(hao)為s的(de)分(fen)(fen)段(duan)發出之后(hou),m秒后(hou),序列(lie)(lie)號(hao)(hao)比s小的(de)序列(lie)(lie)號(hao)(hao)為j的(de)分(fen)(fen)段(duan)發出,只不(bu)過(guo)此(ci)時(shi)的(de)j比上一(yi)(yi)個(ge)(ge)(ge)s多(duo)了一(yi)(yi)圈(quan),這(zhe)就是(shi)回繞問(wen)(wen)題,那么(me)如(ru)果這(zhe)后(hou)一(yi)(yi)個(ge)(ge)(ge)分(fen)(fen)段(duan)到達接(jie)收端(duan),這(zhe)就會(hui)(hui)引(yin)發徹(che)底(di)亂序-本來j該在(zai)(zai)s后(hou)面,結果反而到達前面了,這(zhe)種(zhong)亂序是(shi)TCP協議檢查不(bu)出來的(de)。我(wo)們(men)仔細想一(yi)(yi)下,這(zhe)種(zhong)情況確實(shi)會(hui)(hui)發生(sheng),數據分(fen)(fen)段(duan)并不(bu)是(shi)一(yi)(yi)個(ge)(ge)(ge)字(zi)(zi)節一(yi)(yi)個(ge)(ge)(ge)字(zi)(zi)節發送(song)出去的(de),如(ru)果存在(zai)(zai)一(yi)(yi)個(ge)(ge)(ge)速率為1Gbps的(de)網絡,TCP發送(song)端(duan)1秒會(hui)(hui)發送(song)125MB的(de)數據,32位的(de)序列(lie)(lie)號(hao)(hao)空間能傳(chuan)輸2的(de)32次(ci)方個(ge)(ge)(ge)字(zi)(zi)節,也就是(shi)說32秒左右就會(hui)(hui)發生(sheng)回繞,我(wo)們(men)知道(dao)這(zhe)個(ge)(ge)(ge)值遠(yuan)小于(yu)MSL值,因此(ci)會(hui)(hui)發生(sheng)的(de)。
有個細節可能會引起誤會,那就是(shi)(shi)TCP的窗(chuang)口(kou)大小(xiao)空間(jian)是(shi)(shi)序列(lie)號(hao)空間(jian)的一半(ban),這樣恰好(hao)在(zai)滿載情況下,數據能填滿發送窗(chuang)口(kou)和接收(shou)窗(chuang)口(kou),序列(lie)號(hao)空間(jian)正(zheng)好(hao)夠(gou)用。然(ran)而事(shi)實上(shang),TCP的初(chu)始序列(lie)號(hao)并不是(shi)(shi)從0開(kai)始的,而是(shi)(shi)隨機產生的(當然(ran)要輔助一些更精妙的算法),因此如果初(chu)始序列(lie)號(hao)比較接近2的32次(ci)方,那么很快就會回繞。
當(dang)然,如(ru)今可(ke)(ke)以(yi)用時間戳選項來輔助(zhu)作為(wei)序列號(hao)(hao)的(de)(de)(de)一(yi)(yi)個(ge)識別(bie)的(de)(de)(de)部分,接(jie)(jie)收端遇到(dao)(dao)(dao)回繞(rao)的(de)(de)(de)情(qing)(qing)況,需要比(bi)較(jiao)時間戳,我們知道,時間戳是單調遞增的(de)(de)(de),雖(sui)(sui)然也會(hui)(hui)回繞(rao),然而回繞(rao)時間卻(que)要長很多(duo)。這(zhe)只(zhi)是一(yi)(yi)種(zhong)策略,在(zai)此(ci)不(bu)詳(xiang)談(tan)。還有一(yi)(yi)個(ge)很現實的(de)(de)(de)問題,理論上(shang)序列號(hao)(hao)會(hui)(hui)回繞(rao),但是實際上(shang),有多(duo)少(shao)TCP的(de)(de)(de)端點(dian)主(zhu)機直接(jie)(jie)架設在(zai)1G的(de)(de)(de)網(wang)絡(luo)線(xian)纜兩端并且接(jie)(jie)收方和(he)發送(song)方的(de)(de)(de)窗(chuang)口還能恰好(hao)被同時填滿。另外,就(jiu)算發生(sheng)了回繞(rao),也不(bu)是一(yi)(yi)件特別(bie)的(de)(de)(de)事情(qing)(qing),回繞(rao)在(zai)計(ji)算機里(li)面太(tai)常見了,只(zhi)需要能識別(bie)出來即可(ke)(ke)解決,對(dui)于(yu)(yu)TCP的(de)(de)(de)序列號(hao)(hao)而言(yan),在(zai)高速網(wang)絡(luo)(點(dian)對(dui)點(dian)網(wang)絡(luo)或者(zhe)以(yi)太(tai)網(wang))的(de)(de)(de)兩端,數(shu)據發生(sheng)亂序的(de)(de)(de)可(ke)(ke)能性很小(xiao),因此(ci)當(dang)收到(dao)(dao)(dao)一(yi)(yi)個(ge)序列號(hao)(hao)突然變為(wei)0或者(zhe)終(zhong)止序列號(hao)(hao)小(xiao)于(yu)(yu)起始序列號(hao)(hao)的(de)(de)(de)情(qing)(qing)況后,很容易(yi)辨(bian)別(bie)出來,只(zhi)需要和(he)前一(yi)(yi)個(ge)確認的(de)(de)(de)分段比(bi)較(jiao)即可(ke)(ke),如(ru)果在(zai)一(yi)(yi)個(ge)經過路由器的(de)(de)(de)網(wang)絡(luo)兩端,會(hui)(hui)引(yin)發IP數(shu)據報的(de)(de)(de)順序重排,對(dui)于(yu)(yu)TCP而言(yan),雖(sui)(sui)然還會(hui)(hui)發生(sheng)回繞(rao),也會(hui)(hui)慢得多(duo),且考慮到(dao)(dao)(dao)擁(yong)塞(sai)窗(chuang)口(目(mu)前還沒有引(yin)入)一(yi)(yi)般不(bu)會(hui)(hui)太(tai)大,窗(chuang)口也很難(nan)被填滿到(dao)(dao)(dao)65536。
3.2.4.端到端的流量控制
端到端的(de)流(liu)量控制使用滑(hua)動窗口來(lai)實現。滑(hua)動窗口的(de)原理非常(chang)簡單,基本就是一(yi)個生產者/消費者模型
疑難雜癥10:流(liu)量(liang)控制的真實意義
很多人以為(wei)流量(liang)(liang)控制會很有效(xiao)的協調兩端的流量(liang)(liang)匹配,確實是這(zhe)(zhe)樣,但是如果你考慮到(dao)網(wang)絡(luo)的利(li)用率問(wen)題,TCP的流量(liang)(liang)控制機制就不那么完美(mei)了(le),造(zao)成(cheng)這(zhe)(zhe)種局面的原因(yin)在于,滑動窗口只是限制了(le)發送(song)的數據,卻沒有限制最小發送(song)的數據,結(jie)果導(dao)致(zhi)一(yi)些(xie)很小的數據被封裝成(cheng)TCP分段,報文協議頭所占的比例過(guo)于大,造(zao)成(cheng)網(wang)絡(luo)利(li)用率下降,這(zhe)(zhe)就引出了(le)接(jie)下來的內容,那就是端到(dao)端意義的TCP協議效(xiao)率。
終于到了闡述問題的時候了,以上的TCP協議實現的非常簡單,這也是TCP的標準實現,然而很快我們就會發現各種各樣的問題。這些問題導致了標準化協會對 TCP協議進行了大量的修補,這些修補雜糅在一起讓人們有些云里霧里,不知所措。本文檔就旨在分離這些雜亂的情況,實際上,根據RFC,這些雜亂的情況都是可以找到其單獨的發展軌跡的。