手冊-tcpip詳解卷2實現(xiàn)_第1頁
手冊-tcpip詳解卷2實現(xiàn)_第2頁
手冊-tcpip詳解卷2實現(xiàn)_第3頁
手冊-tcpip詳解卷2實現(xiàn)_第4頁
手冊-tcpip詳解卷2實現(xiàn)_第5頁
免費預覽已結(jié)束,剩余27頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第29 TCP的輸入(續(xù)本章從前一章結(jié)束的地方開始,繼續(xù)介紹TCP輸入處理。回想一下圖28-37中最后的測試本章處理ACK標志,更新窗口信息,處理URG標志及報文段中攜帶的所有數(shù)據(jù),最后處在本章中,首先ACK的處理,圖29-1給出了ACK處理的框架。SYN_RCVD狀態(tài)需要特殊處理,緊跟著是其他狀態(tài)的通用處理代碼(前一章已過在LISTEN和SYN_SENT狀態(tài)下收到ACK時的處理邏輯)TCPS_FIN_AIT_1、TCPS_CLOSING和TCPS_LAST_ACKACK會導致狀態(tài)的轉(zhuǎn)移。此外,在TIME_AIT狀態(tài)下收到ACK還會導致2MSL定時器的重啟。圖29-1ACK圖29-1(續(xù)圖29-2給出了如何處理SYN_RCVD狀態(tài)下收到的ACK報文段。如前一章中提到過的,這也將完成打開(一般情況),或者是同時打開及自連接(特殊情況)的連接建立過程。驗證收到的801-806Na(將snd_una設(shè)定為連接的ISS,SYN報文段的序號),且小于等于snd_max。如果條件滿足,則插口進入連接狀態(tài)ESABLISHED。在收到三次握手的最后一個報文段后,調(diào)用soisconnected喚醒打開的應(yīng)用進程一般為服務(wù)器)。如果服務(wù)器在調(diào)用accept上阻塞,則該調(diào)用現(xiàn)在返回。如果服務(wù)器調(diào)用807-812如果TCP曾發(fā)送窗口大小選項,并且收到了對方的窗口大小選項,則在TCP控制塊中保存發(fā)送縮放因子和接收縮放因子。另外,TCP控制塊中的snd_scale和rcv_scale的默認值為0無縮放)。813現(xiàn)在可以向應(yīng)用進程提交連接重組隊列中的數(shù)據(jù),調(diào)用tcp_reass,第二個參數(shù)為空。重組隊列中的數(shù)據(jù)可能是SYN報文段中攜帶的,它同時將連接狀態(tài)變遷為SYN_RCVD。81 snd_wl1等于收到的序號減1,從圖29-15可知,這樣將導致更新3圖29-3給出了ACK處理的下一部分代碼,處理重復ACK,并決定是否起用TCP的快速重傳和快速恢復算法[Jacobson1990c][Floyd1994]??焖僦貍魉惴ㄓ糜谶B續(xù)出現(xiàn)幾次(一般為3次)重復ACK時,TCP認為某個報文段已丟失并且從中推斷出丟失報文段的起始序號,丟失報文段被重傳。RFC1122中的1節(jié)提到了這一算法,建議TCP收到亂序報文段后,立即發(fā)送ACK??吹剑趫D27-15中,Net/3正是這樣做的。這個算法最早出現(xiàn)在4.3BSDTahoe版及后續(xù)的Net/1實現(xiàn)中,(即丟失報文段已重傳),應(yīng)執(zhí)行擁塞避免算法,而非慢起動。這樣,如果擁塞不嚴重,還能保證較大的吞吐量,尤其窗口較大時。這個算法最早出現(xiàn)在4.3BSDReno版和后續(xù)的Net/2實現(xiàn)中。在圖24-17節(jié)中,提到有效的ACK必須滿足下面的不等式:snd_una確認字段第一步只與snd_una29-5中再進行不等式第二部分的比較。分開比較的原因是為了能對收到的ACK完成下列5項測試:如果確認字段小于等于snd_una;并接收報文段長度為0;并窗口通告大小未變連接上部分發(fā)送數(shù)據(jù)未被確認(重傳定時器非零);并接收報文段的確認字段是TCP收到的最大的確認序號(確認字段等于snd_una)之后可確認報文段是完全重復的ACK(測試項1、2和3在圖29-3中,測試4和5在圖29-4的起始TCP統(tǒng)計連續(xù)收到的重復ACK的個數(shù),保存在變量t_dupacks中,次數(shù)超過門限(tcprexmtthresh,3)時,丟失報文段被重傳。這也就是卷1第21.7節(jié)中介紹的快速重傳算法。它與圖27-15中的代碼互相配合:當TCP收到亂序報文段時,立即生成一個重復的ACK,告訴對端報文段有可能丟失和等待接收的下一個序號值??焖僦貍魉惴ㄊ菫榱俗孴CP立即重傳看上去已經(jīng)丟失的報文段,而不是地等待重傳定時器超時。卷1第21.7節(jié)舉例詳細說明了圖29-3tcp_input函數(shù):判定完全重復的ACK了一個亂序報文段,從而開始發(fā)送重復的ACK。快速恢復算法要求連續(xù)收到幾個重復ACK后,TCP應(yīng)該執(zhí)行擁塞避免算法(如降低速度),而不一定必需等待連接兩端間的管道清空(慢起動)?!半x開了網(wǎng)絡(luò)”指數(shù)據(jù)分組已被對端接收,并加入到連接的重組隊列中,不再滯留在傳輸途如果前述5項測試條件只有前3項為真,說明ACK是重復報文段,統(tǒng)計值ck加1,而連續(xù)重復ACK計數(shù)器(t_dupacks)復位為0。如果僅有第一項測試條件為真,則計數(shù)器t_dupacks復位為0。圖29-4給出了快速重傳算法其余的代碼,當所有5個測試條件全部滿足時,根據(jù)已連續(xù)收t_dupacks等于3(tcprexmtthresh),則執(zhí)行擁塞避免算法,并重傳丟失報文t_dupacks大于3,則增大擁塞窗口,執(zhí)行正常的TCP輸出t_dupacks小于3,不做圖29-4tcp_input函數(shù):處理重復的連續(xù)收到的重復ACK次數(shù)己達到門限值861-868t_dupacks等于3(tcprexmtthresh)時,在變量onxt中保存snd_nxt值,令慢起動門限(ssthresh)等于當前擁塞窗口大小的一半,最小值為兩個最大報文段長度。這與圖25-27中重傳定時器超時處理中的慢起動門限設(shè)定操作類似,但看到,超時處理中把擁塞窗口設(shè)定為一個最大報文段長度,快速重傳算法并不這樣做。869870關(guān)閉重傳定時器。為防止TCPt_rtt871873從連續(xù)收到的重復ACK報文段中可判斷出丟失報文段的起始序號(重復ACK的確認發(fā)送丟失報文段(參見卷1的圖21-7中的63號報文段)。874-875擁塞窗口等于慢起動門限加上對端高速緩存的報文段數(shù)?!案咚倬彺妗敝笇Χ艘咽盏降膩y序報文段數(shù),且為這些報文段發(fā)送了重復的ACK。除非對端收到了丟失的報文段(剛剛發(fā)送),這些緩存報文段中的數(shù)據(jù)不會被提交給應(yīng)用進程。卷1的圖21-10和圖21-11給出了快速設(shè)定876-878比較下一發(fā)送序號(snd_nxt)的先前值(onxt)和當前值,將兩者中最大的一個重新賦還給snd_nxt,因為重傳報文段時,tcp_output會改變snd_nxt。一般情況下,snd_nxt將等于原來保存的值,意味著只有丟失報文段被重傳,下一次調(diào)用tcp_output時,連續(xù)收到的重復ACK數(shù)超過門限879-883 因為t_dupacks等于3時,已重傳了丟失的報文段,再次收到重復ACK說明又有另一個報文段離開了網(wǎng)絡(luò)。擁塞窗口大小加1,調(diào)用tcp_output發(fā)送序列中的下一報文段,884885ACK,且長度非零或者通告窗口大小發(fā)生變化,則執(zhí)行這些語句。此時,前面提到的5個測試條件中只有第一個為真,連續(xù)收到的重復ACK數(shù)被略過ACK處理的其余部886 break語句在下列3(1)前述5(2)只有前3個條件為真;(3)重復ACK次數(shù)小于門限值3。任何一種情況下,盡管收到的是重復ACK,將執(zhí)行break語句,控制跳到圖29-2中switch語句的結(jié)尾處,在標注step6處繼續(xù)8而本地報文段1~8已發(fā)送。報文段1丟失,其余報文段均正常到達且被確認。收到對報文段2、3和4的確認后,重傳丟失的報文段(15~8TCP夠發(fā)送報文段9,以高的吞率但窗口小于8,送報文段9及其后續(xù)報文段。因此,每當再次收到一個重復的ACK,就暫時把擁塞窗口加1,因為收到重復的ACK告訴TCP1的確認后,下面將介紹的代碼會減少擁塞窗口大小,令其等于慢起動門限。卷1的圖21-10舉例說明了這一過程,重復ACK到達時,增加擁塞窗口大小,之后收到新的ACK時,再相應(yīng)地減少擁塞窗口。圖29-5中的代碼繼續(xù)處理ACK888-895如果連續(xù)收到的重復ACK數(shù)超過了門限值3,說明這是在收到了4個或4個以上的重復ACK后,收到的第一個非重復的ACK??焖僦貍魉惴ńY(jié)束。因為從收到的第4個重復ACK開始,每收到一個重復ACK就會導致?lián)砣翱诩?,如果它已超過了慢起動門限,令其檢查ACK的有效896899前面介紹過,有效的ACKsnd_una確認字段<=如果確認字段大于snd_max,可對端正在確認了TCP尚未發(fā)送的數(shù)據(jù)。可能的原因是,對于高速連接,某個的ACK再次出現(xiàn)時,序號已回繞,從圖24-5可知,這是極為罕見的900902經(jīng)過前面的測試,已知這是一個有效的ACK。acked等于確認的字節(jié)數(shù)。903-915如果(1)時間戳選項存在;或者(2)TCP對某個報文段計時,且收到的確認字段大于該報文段的起始序號,則調(diào)用tcp_xmit_timer更新RTT測算值。注意,使用時間戳時,tcp_xmit_timer的第二個參數(shù)等于當前時間(tcp_now)減去收到的時間戳回顯(ts_ecr)由于延遲ACK的存在,面的測試不等式中應(yīng)采用大于號。例如,假定TCP發(fā)送了一1~10241025~2048。如果收到的確認字段等于2049,因為2049大于1(計文段的起始序號),TCP將更新TT測算值。916-924如果收到報文段的確認字段(ti_ack)等于TCP的最大發(fā)送序號(snd_max),說明所有已發(fā)送數(shù)據(jù)都已被確認。關(guān)閉重傳定時器,并置位needoutput標志,從而在函數(shù)結(jié)束時強迫調(diào)用tcp_output。這是因為在此之前,有可能因為發(fā)送窗口已滿,TCP了等待發(fā)送的數(shù)據(jù),而現(xiàn)在收到了新的ACK,確認了全部已發(fā)送數(shù)據(jù),發(fā)送窗口能夠向右移動(圖29-8中的snd_una被更新),允許發(fā)送的數(shù)據(jù)。925-926 注意,時間戳的運用取消了Karn算法的部分規(guī)定(卷1的21.3節(jié)):如果重傳定時器超時,則報文段被重傳,收到對重傳報文段的確認時,不應(yīng)據(jù)此更新TT測算值(重傳確認的二義性問題)。在圖25-26中,看到當發(fā)生重傳時,遵從Karn,t_rtt被設(shè)為0。如果時間戳不存在,且收到的是對重傳報文段的確認,則圖29-中的代碼不會更新TT測算值,因為此時t_rtt等于0。但如果時間戳存在,則不查看t_rtt值,允許利用收到的時間戳回顯字段更新TT測算值。根據(jù)RFC1323,時間戳的運用不存在二義性,因為ts_ecr的值自被確認的報文段。Karn算法中關(guān)于重傳報文段時應(yīng)采用指數(shù)退避的策略依舊有效。圖29-7給出了ACK處理的下一部分代碼,更新?lián)砣皥D29-7tcp_input函數(shù):響應(yīng)收到的ACK

圖29-7續(xù)927-94 慢起動和擁塞避免的一條原則是收到ACK到一個ACK(慢起動),擁塞窗口將加1。但如果當前擁塞窗口大于慢起動門限,增加值等于incr*incr/t_maxseg*t_maxseg/即1除以擁塞窗口,因為snd_cwnd的單位為字節(jié),而非報文段。表達式的常量部分等于最大報文段長度的1/8。此外,擁塞窗口的上限等于連接發(fā)送窗口的最大值。算法的舉例參見卷的21.8添加一個常量最大報文段長度的1/8)是錯誤的[Floyd1994]BSD源碼中,從4.3BSD到4.4BSD和Net/3圖29-8給出了tcp_input下一部分的代碼,從發(fā)送緩存中刪除已確認的數(shù)94394 如果確認字節(jié)數(shù)超過發(fā)送緩存中的字節(jié)數(shù),則從snd_wnd節(jié)數(shù),并且可知本地發(fā)送的FIN已被確認。調(diào)用sbdrop從發(fā)送緩存中刪除所有字節(jié)。能夠以這種方式檢查對FIN報文段的確認,是因為FIN在序號空間中只占一個字節(jié)。947-951如果確認字節(jié)數(shù)小于或等于發(fā)送緩存中的字節(jié)數(shù),ourfinisacked等于0,并從951-956調(diào)用sowwakeup喚醒所有等待發(fā)送緩存的應(yīng)用進程,更新snd_una保存最老的未被確認的序號。如果snd_una的新值超過了snd_nxt,則更新后者,因為這說明中間的數(shù)據(jù)也被確認。圖29-9舉例說明了為什么snd_nxt保存的序號有可能小于snd_una。假定傳輸了兩個報文段,第一個攜帶字節(jié)1~512,而第二個攜帶字節(jié)513~1024。一一個報一個報圖29-9確認返回前,重傳定時器超時。圖25-26中的代碼將snd_nxt設(shè)定為snd_una,進入慢起動狀態(tài),調(diào)用tcp_output重傳攜帶1~512字節(jié)的報文段。tcp_output將snd_nxt增加為513,如圖29-10所示。 報文段重 圖29-10重傳定時器超時后的連接(接圖29-此時,確認字段等于1025的ACK到達(或者是最初發(fā)送的兩個報文段或者是ACK在網(wǎng)絡(luò)中被延遲)。這個ACK是有效的,因為它小于等于snd_max,但它也將小于更新后的snd_una值。一般性的ACK處理現(xiàn)在已結(jié)束,圖29-11中的switch語句接著處理了4種特殊情況圖29-11tcp_input函數(shù):在FIN_WAIT_1狀態(tài)時收到了在FIN_WAIT_1狀態(tài)時收到了

圖29-11(續(xù)958-971TCP已發(fā)送了FIN,但還有可能收到對在FIN之前發(fā)送的報文段的確認。因此,只有在收到FIN的確認后,連接才會轉(zhuǎn)移到FIN_AIT_2圖29-8ourfinisacked標志已置位,這取決于確認的字節(jié)數(shù)是否超過發(fā)送緩存中的數(shù)據(jù)量。設(shè)定FIN_WAIT_2定時972-975在256節(jié)中介紹了Net3如何設(shè)定FINAI_定時器,以防止在INWAI_2狀態(tài)無限等待。只有當應(yīng)用進程完全關(guān)閉了連接(如號量終止時與類似的內(nèi)核調(diào)用),而不是半關(guān)閉時(如已發(fā)送了FIN上接收數(shù)據(jù)圖29-12給出了在CLOSING狀態(tài)收到ACK時的處理代碼圖29-12tcp_input函數(shù):在CLOSING狀態(tài)收到在CLOSING狀態(tài)收到979-992如果收到的ACK是對FIN的確認()MEAIT狀態(tài)。所有等待的定時器都被清除(如等待的重傳定時器),IMEAIT定時器被啟動,時限等于兩倍的MS。圖29-13給出了在LAST_ACK狀態(tài)收到ACK的處理代碼圖29-13tcp_input函數(shù):在LAST_ACK狀態(tài)收到在LAST_ACK狀態(tài)收到993-1004如果FIN已確認,連接將轉(zhuǎn)移到CLOSED狀態(tài)。tcp_close將負責這一狀態(tài)變遷,并同時InternetPCB和TCP控制塊。圖29-14給出了在TIME_WAIT狀態(tài)收到ACK的處理代在TIME_WAIT狀態(tài)收到1005-1014此時,連接兩端都已發(fā)送過FIN,且兩個FIN都已被確認。但如果TCP對遠端FIN的確認丟失,對端將重傳FIN帶有ACK。TCP丟棄報文段并重傳ACK。此外,TCP控制塊中還有兩個窗口變量未曾提及:snd_wl1和snd_wl2nd_wl1記錄最后接收報文段的序號,用于更新發(fā)送窗口(snd_wnd)snd_wl2記錄最后接收報文段的確認序號,用于更新發(fā)送窗到目前為止,只在連接建立時(主動打開、打開或同時打開)遇到過這兩個變量,snd_wl1被設(shè)定為ti_seq減1。當時說是為了保證窗口更新,下面的代碼將證明這一如果下列3個條件中的任一個被滿足,則應(yīng)根據(jù)接收報文段中的通告窗口值(tiwin)更新發(fā)報文段攜帶了新數(shù)據(jù)。因為snd_wl1保存了用于更新窗口的最后接收報文段的起號,如果snd_wl1<ti_seq,說明此條件為報文段未攜帶新數(shù)據(jù)(snd_wl1等于ti_seq),但報文段確認了新數(shù)據(jù)。因為snd_wl2<ti_ack報文段未攜帶新數(shù)據(jù),也未確認新數(shù)據(jù),但通告窗口大于當前發(fā)送這些測試條件的目的是為了防止舊的報文段影響發(fā)送窗口,因為發(fā)送窗口并非序號序列,而是從snd_una算起的偏移量。10151023if語句檢查報文段的ACK標志是否置位,且前述3個條件中是否有一個被滿足。前面介紹過,在LISTEN狀態(tài)或SYN_SENT狀態(tài)收到SYN后,控制將跳轉(zhuǎn)到step6,而在注釋中的TAC指“終端接入控制器(terminalaccesscontroller)”,是ARPANET上 1024-1027如果收到一個純窗口更文段(長度為0,ACK未確認新數(shù)據(jù),但通告窗口增1028-1033更新發(fā)送窗口,保存新的snd_wl1和snd_wl2值。此外,如果新的通告窗口是TCP從對端收到的所有窗口通告中的最大值,則新值被保存在max_sndwnd中。這是為了猜測對端接收緩存的大小,在圖26-8中用到了此變量。更新snd_wnd后,發(fā)送窗口可用空間增加,從而能夠發(fā)送新的報文段,因此,needoutput標志置位。TCP輸入處理的下一部分是URG標志置位時的報文段。如圖29-16所示是否需要處理URG1035-1039只有滿足下列條件的報文段才會被處理:URG標志置位,緊急數(shù)據(jù)偏移量(ti_urp)非零,連接還未收到FIN。只有當連接的狀態(tài)等于TIME_WAIT時,宏TCPS_HAVERCVDFIN才會為真,因此,連接處于任何其他狀態(tài)時,URG都會被處理。在后面的注釋中提到,連接處于CLOSE_WAIT、CLOSING、LAST_ACK和TIME_AIT等幾個狀態(tài)時,URG標志會被忽略,這種說法是錯誤的。1040-1050如果緊急數(shù)據(jù)偏移量加上接收緩存中已有的數(shù)據(jù)超過了插口緩存可容納的數(shù)據(jù)量,則忽略緊急標志。緊急數(shù)據(jù)偏移量被清零,URG標志被清除,剩余的緊急方式處理邏輯圖29-17給出了tcp_input下一部分的代碼,處理緊急圖29-17(續(xù)1051-1065明已收到了一個新的緊急指針。例如,圖26-30中的攜帶3字節(jié)的報文段到達接收方,如圖29-接收報緊急數(shù)據(jù)偏移一般情況下,收到的緊急指針(rcv_up)等于rcv_nxt。這個例子中,因為if語句接收報緊急數(shù)據(jù)偏移1066-1070的分界點,應(yīng)計入接收緩存中已有的數(shù)據(jù)(so_rcv.sb_cc)在面的例中假定接收緩存為空, 等2:序號為

圖29- 點上。如果發(fā)送帶外數(shù)據(jù)的d系統(tǒng)調(diào)用給定長度為1,并且這個報文段到達對端時接收緩存為空,就會發(fā)生這一現(xiàn)象,同時也再次重申了Bkeley系統(tǒng)認為緊急指針應(yīng)指向帶外數(shù)據(jù)后的向應(yīng)用進程通告TCP的緊1071-1072調(diào)用sohasoutofbandTCPOOB_HAVEDATA和TCPOOB_HADDATA,它們用于圖30-8中的PRU_RCVOOB請求處理1074-1085 如果緊急數(shù)據(jù)偏移量小于等于接收報文段中的字節(jié)數(shù),說明帶外數(shù)據(jù)包含在報文段中。TCP的緊急方式允許緊急數(shù)據(jù)偏移量指向尚未收到的數(shù)據(jù)。如果定義了SO_OOBINLINE常量(Net/3定義了此常量),而且未選用對應(yīng)的插口選項,則接收進程從常的數(shù)流提取帶數(shù),并保在t_iobc變量中。完成這能的函數(shù),是在下一節(jié)介紹的tcp_pulloutofband。注意,無論緊急指針指向的字節(jié)是否可讀,TCP都將通知接收進程發(fā)送方已進入緊急方式。1086-1093在接收處理緊急指針時,如果rcv_nxt大于接收緊急指針,則rcv_up向右移動,并等于rcv_nxt。這使接收緊急指針一直指向接收窗口的左側(cè),確保在收到URG標如果要實現(xiàn)習題26.6中方案,也必須相應(yīng)修改圖29-16和圖29-17中的接收報文段中帶有緊急方式標志帶外數(shù)據(jù)包含在接收報文段中(如,緊急指針指向接收報文段);并未選用SO_OOBINLINE選項函數(shù)從正常的數(shù)據(jù)流(保存接收報文段的mbuf鏈中提取帶外字節(jié),并保存在連接TCP控制塊中的t_iobc變量中。應(yīng)用進程通過recv系統(tǒng)調(diào)用,置位MSG_OOB標志,這個變量圖30-8中的PRU_RCVOOB請求。圖29-19給出了函數(shù)代碼。圖29-19(續(xù)12821289考慮圖29-203,因此緊急指針等于7,帶外字節(jié)變量cnt等于2,因為m_len(等于5)大于2,執(zhí)行if語句為真部分的代12901298cp指向序號6的字節(jié),它被放入保存帶外字節(jié)的變量t_iobc中。置位TCPOOB_HAVEDATA標志,調(diào)用bcopy將接下來的兩個字節(jié)(序號7和8)左移1字節(jié),如圖29-接收接收報緊急數(shù)據(jù)偏移圖29- 圖29- 移走帶外數(shù)據(jù)后的結(jié)果(接圖29-注意,數(shù)字7和8指數(shù)據(jù)字節(jié)的序號,而不是其內(nèi)容。mbuf的長度從5減為4但ti_len仍等于5不變,這是為了按序把報文段放入插口的接收緩存。TCP_REASS宏和tcp_reass函數(shù)(在下一節(jié)調(diào)用)會給rcv_nxt增加ti_len,本例中ti_len必須等于5,因為下一個等待接收的序號等于9。還請注意,函數(shù)沒有對第一個 mbuf中的數(shù)據(jù)分組首部長度(m_pkthdr.len)減1,這是因為負責把數(shù)據(jù)添加到插口接收緩存的sbappend不使用此長度值。跳至鏈中的下一個1299-1302如果帶外數(shù)據(jù)未保存在此mbuf中,則從cnt中減去mbuf中的字節(jié)數(shù),處理鏈中的下一個mbuf。因為只有當緊急數(shù)據(jù)移量指向接收報文段時,才會調(diào)用此函數(shù),所以,如果鏈已結(jié)束,不存在下一個mbuf,則執(zhí)行break語句,跳轉(zhuǎn)到標注panic處。tcp_input接著提取收到的數(shù)據(jù)(如果存在),將其添加到插口接收緩存,或者放入插口的亂序重組隊列中。圖29-22給出了完成此項功能的代碼。10941105接收數(shù)據(jù)的長度大于0,或者FIN標志置位;并連接還未收到則調(diào)用宏TCP_REASS處理數(shù)據(jù)。如果數(shù)據(jù)次序正確(如,連接等待接收的下一序號),置位延遲ACK標志,增加rcv_nxt,并把數(shù)據(jù)添加到插口的接收緩存中。如果數(shù)據(jù)次序錯誤,宏會調(diào)用tcp_reass函數(shù),把數(shù)據(jù)加入到連接的重組隊列中(新到數(shù)據(jù)有可能填充隊列中的缺口,從而將已排隊的數(shù)據(jù)添加到插口的接收緩存中)。前面介紹過,宏的最后一個參數(shù)(tiflags)是可修改的。特別地,如果數(shù)據(jù)次序錯誤,tcp_reass令tiflags等于0,清除FIN標志(如果它已置位)。這也就是為什么即使報文段中沒有數(shù)據(jù),只要FIN置位,if語句也為真??紤]下面的例子。連接建立后,發(fā)送方立即發(fā)送報文段:一個攜帶字節(jié)1~1024,另一個攜帶字節(jié)1025~2048,還有一個未帶數(shù)據(jù)的FIN。第一個報文段丟失,因此,第二個報文段到達時(字節(jié)1025~2048)ACK。當?shù)谌齻€帶有FIN29-220,因為FIN置位,導致調(diào)用TCP_REASS,它接著調(diào)用tcp_reass。因為ti_seq(2049,F(xiàn)IN的序號)不等于rcv_nxt(1),tcp_reass返回0(圖27-23)。在TCP_REASStiflags被設(shè)為0,從而清除了FIN標志,后續(xù)代碼(圖29-10)繼續(xù)處理FIN。1106-1111計算len,實際上是在猜測對端發(fā)送緩存的大小??紤]下面的例子。插口接收緩存大小等于8192(Net/3的默認值)TCP在SYN8192。之后收到第一個報文段,攜帶字節(jié)1~1024。圖29-23給出了在TCP_REASS增加rcv_nxt以反應(yīng)收到的數(shù)據(jù)后接收空間的狀態(tài)。圖29-23大小為8192的接收窗口收到字節(jié)1~1024此時,經(jīng)計算,len等于1024。對端向接收窗口發(fā)送數(shù)據(jù)后,len值將增加,但絕不會超過對端發(fā)送緩存的大小。前面介紹過,圖29-15中對變量max_sndwnd的計算,是在猜測事實上,變量len從未被使用。它是從Net/1遺留下來的,len計算后被TCP控制塊的max_rcvd變量中if(len>tp->max_rcvd)tp->max_rcvd=len;但即使在Net/1中,變量max_rcvd也未被使用1112-1115如果len等于0,且FIN標志未置位,或者連接上已收到了FIN,則丟棄保存接tcp_input的下一步,在圖29-24中給出,處理FIN標志處理收到的第一個1116-112 如果接收報文段FIN置位,并且是連接上收到的第一 FIN,則調(diào)socantrcvmore,把插口設(shè)為只讀,置位TF_ACKNOW,從而立即發(fā)送ACK()rcv_nxt加1,越過FIN占用的序號1126FIN處理的其余部分是一個大的switch語句,根據(jù)連接的狀態(tài)進行轉(zhuǎn)換。注意,連接處于CLOSE、LISTEN和SYN_SENT狀態(tài)時,不處理FIN,因為處于這3個狀態(tài)時,還未收到對端發(fā)送的SYN,無法同步接收序號,也就無法驗證FIN序號的有效性。此外,連接處于CLOSING、CLOSE_WAIT和LAST_ACK狀態(tài)時,也不處理FIN,因為在這3個狀態(tài)下收到的FIN必然是一個重復報文段。SYN_RCVD和ESTABLISHED1127-1134如果連接處于SYN_RCVD或ESTABLISHED狀態(tài),收到FIN盡管在SYN_RCVD狀態(tài)下收到FIN是合法的,但卻極為罕見。圖24-15的狀態(tài)圖未列出這一狀態(tài)變遷。它意味著處于LISTEN狀態(tài)的插口收到一個同時帶有SYN和FIN的報文段?;蛘?,正在的插口收到了SYN,連接轉(zhuǎn)移到SYN_RCVD狀態(tài),但在收到ACK之前,先收到了FIN(FIN未攜帶有效的ACK,否則,圖29-2中的代碼會使連接轉(zhuǎn)移到ESABLISHED狀態(tài))。圖29-25給出了FIN處理的下一部FIN_WAIT_11135-1141因為報文段的ACK處理已結(jié)束,如果處理FIN時,連接處于FIN_WAIT_1狀態(tài),意味著連接兩端同時關(guān)閉連接—兩端發(fā)送的兩個FIN在網(wǎng)絡(luò)錯。連接進入CLOSING狀態(tài)FIN_WAIT_21142-1148 收到FIN將使連接進入TIME_AIT狀態(tài)。當在FIN_AIT_1狀態(tài)收到攜帶ACK和FIN的報文段時(典型情況),盡管圖24-15顯示連接直接從FIN_WAIT_1轉(zhuǎn)移到TIME_AIT狀態(tài),但在圖29-1中處理ACK時,連接實際已進入FIN_AIT_2狀態(tài)。此處的FIN處理再將連接轉(zhuǎn)到TIME_AIT狀態(tài)。因為ACK在FIN之前處理,所以連接總會經(jīng)過FIN_AIT_2盡管是暫時性的。啟動TIME_WAIT定時1149-1152 關(guān)閉所有等待的TCP定時器,并啟動TIME_AIT定時器,時限等于MSL(接收報文段中包含ACK和FIN,圖29-1中的代碼會啟動FIN_AIT_2定時器)TIME_WAIT1153-1159如果在TIME_WAIT狀態(tài)時收到FIN,說明這是一個重復報文段。與圖29-14中圖29-26給出了tcp_input函數(shù)中首部失敗時,較慢的執(zhí)行路徑中最后一部分的代碼,以及標注dropafterack。SO_DEBUG插口選

1161-1162如果選用了SO_DEBUG插口選項,則調(diào)用tcp_trace向內(nèi)核的環(huán)形緩存中添加記錄?;叵胍幌拢瑘D28-7中的代碼同時保存了原有連接狀態(tài),IP和TCP的首部,因為函數(shù)有調(diào)用1163-1168如果needoutput標志置位(圖29-6和圖29-15),或者需要立即發(fā)送ACK,則調(diào)1169-1179只有當RST標志未置位時,才會生成ACK(帶有RST的報文段不會被確認),釋圖29-27結(jié)束tcp_input函數(shù)

11801188除了接收報文段也有RST此處的代碼存在與圖28-16同樣的錯誤:它查接收報文段的目的地址是否為類似地 IN_MULTICAST的目的地址參數(shù)應(yīng)轉(zhuǎn)換為主機字節(jié)序11891196RST報文段的序號字段值、確認字段值和ACK標志取決于接收報文段中是否帶圖29-28總結(jié)了生成RST報文段中的這些字段接收到的報文生成的RST序號不帶接收到的確認字00接收到的序號字圖29- 生成RST報文段各字段的正常情況下,除了起始的SYN(圖24-16),所有報文段都帶有ACK。tcp_respond的第1192-1193 如果SYN置位,則ti_len必須加1,從而生成RST的確認字段比收到的SYN報1。如果到達的SYN請求與不存在的服務(wù)器建立連接,會執(zhí)行這一段代碼。此時,由于圖28-6中的代碼找不到請求的InternetPCB,控制跳轉(zhuǎn)到dropwithreset。但為了使發(fā)送的RST能被對端接受,報文段必須確認SYN(圖28-18)。卷1的18.14節(jié)舉例說明了這種類型的RST。最后請注意,tcp_respond利用保存接收報文段的第一個mbuf構(gòu)造RST,并且鏈上1197-1199如果在圖28-7中為的服務(wù)器創(chuàng)建了臨時的插口,但圖28-16中的代碼發(fā)現(xiàn)接收報文段有錯誤,它會置位dropsocket。如果出現(xiàn)了這種情況,插口在此處被。丟棄(不帶ACK或1201-1206 如果接收報文段被丟棄,且不生成ACK或RST,則調(diào)用tcp_trace。如果SO_DEBUG置位且生成了ACK,則tcp_output將向內(nèi)核的環(huán)形緩存中添加一條記錄。如果SO_DEBUG置位且生成了RST,系統(tǒng)不會為RST添加新的記錄。1207-1211保存接收報文段的mbuf鏈。如果dropsocket非零,則臨時創(chuàng)建的插為了加速TCP處理而進行的優(yōu)化與UDP類似(23.12節(jié))。應(yīng)利用數(shù)據(jù)計算檢驗和,并避免在處理中多次遍歷數(shù)據(jù)。[Daltonetal.1993]了這些修訂。連接數(shù)增加時,對TCPPCB的線性搜索也是一個處理瓶頸。[McKenneyandDove1992]討[Partridge1993]介紹了VanJacobson開發(fā)的一個用于研究目的的協(xié)議實現(xiàn),極大地減少了TCPIP進行處理(RISC系統(tǒng)中約有25條指令),之后由分用器(demultiplexer)尋找PCB(約10條指令),最后由TCP處理(約30條指令)。這30條指令完成了首部,并計算偽首部檢驗和。如果數(shù)據(jù)報文段通過了首部,且應(yīng)用進程正等待接收數(shù)據(jù),則數(shù)據(jù)到應(yīng)用進程緩存,計算TCP檢驗和并完成驗證(一次遍歷中完成數(shù)據(jù)和檢驗和計算)。如果TCP首部失敗,則執(zhí)行TCP輸入處理中較慢的路徑。下面介紹TCP首部壓縮。盡管首部壓縮不是TCP輸入處理的一部分,但需要徹底了解的工作機制后,才能很好地理解首部壓縮。RFC1144[Jacobson1994a]中詳細定義了首部壓縮,因為VanJacobson首先提出了這一算法,通常也稱為VJ首部壓縮。本節(jié)的目的不是詳細首部壓縮的源代碼(RFC1144給出了實現(xiàn)代碼,其中有很好的注釋,程序量與tcp_output差不多),而是概括性地介紹一下算法的思想。請注意區(qū)分首部(28.4節(jié))和首部壓縮。多數(shù)的SLIP和PPP實現(xiàn)支持首部壓縮。盡管首部壓縮,在理論上,適用于任何數(shù)據(jù)鏈路,但主要是向慢速行路。首壓只處理TCP報文段—與其他的IP協(xié)議無關(guān)(如ICM、IGMP、UDP等等)。它能夠把IP/TC組合首部從正常的40字節(jié)壓縮到只有3字節(jié),從而降低了交互性應(yīng)用,如登錄或 net中TCP報文段的大小,從典型的41字節(jié)減少到只剩4字節(jié)—大大提高了慢速串行鏈路的效串行鏈路的兩端,每端都著兩個連接狀態(tài)表,一個用于數(shù)據(jù)報的發(fā)送,另一個用于256條記錄,但典型的只有1616條不同的TCP8bit的連接ID(限制記錄數(shù)最多只能為256)、某些標志和最近接收/96bit的插口對可惟一確定一條連接—源端IP地址和TCP端口、目的IP地址和TCP端口—這些信息都保存在未壓縮的首部中。圖29-29舉例說明了這些表的結(jié)構(gòu)。發(fā)送連接狀態(tài)標號標 最近的/P首接收連接狀態(tài)標號標 最近的IP/T首接收連接狀態(tài)標號標 最近的IP/T首發(fā)送連接狀態(tài)標號標 最近的IP/T發(fā)送連接狀態(tài)標號標 最近的/P首接收連接狀態(tài)標號標 最近的IP/T首接收連接狀態(tài)標號標 最近的IP/T首發(fā)送連接狀態(tài)標號標 最近的IP/T首圖29- 鏈路(如SLIP鏈路)兩端的一組連接狀態(tài)在圖29-29中利用數(shù)組表示這些表,但在源代碼中,表項定義為一個結(jié)構(gòu),連接狀態(tài)表定義為這些結(jié)構(gòu)組成的環(huán)形鏈表,最近一次用過的結(jié)構(gòu)位于表頭。因為連接兩端都保存了最近用過的未壓縮的數(shù)據(jù)報首部,所以只需在鏈傳送當前數(shù)據(jù)報與前一數(shù)據(jù)報不同的字段及一個特殊的前導字節(jié),指明后續(xù)的是哪一個字段)。因為某些首部字段在相鄰的數(shù)據(jù)報之間不會變化,而其他的首部字段變化也很小,這種差分處理是壓縮算法的。首部壓縮只適用于IP和TCP首部—TCP報文段的數(shù)據(jù)部分不圖29-30給出了發(fā)送方利用首部壓縮算法,在串行鏈發(fā)送IP數(shù)據(jù)報時采取的步驟待待發(fā)送的數(shù)據(jù)非TCP報文壓縮的TCPIP其 找COMPRESSED_TCP無 壓未找PRESSED_TCP壓配的96-bit插口檢查數(shù)圖29- IP型數(shù)據(jù)報,前導字節(jié)的4比特等于4。這也是IP首部中正常的IP版本號(圖8-8),COMPRESSED_TCP型數(shù)據(jù)報,前導字節(jié)的最置為1,類似于IP版本號介于8和15之間(剩余的7bit由壓縮算法使用),說明鏈發(fā)送的是壓縮過的首部和未壓縮的數(shù)據(jù),接下來PRESSED_TCP型數(shù)據(jù)報,前導字節(jié)的4比特等于7,說明鏈發(fā)送的是正常的、未壓縮的數(shù)據(jù)報,但IP的協(xié)議字段(等于6,對TCP)被替換為連接ID,接收方可據(jù)此看數(shù)個導其代圖5-13。圖5-16中,發(fā)送方調(diào)用 press_tcp確認TCP報文段是可壓縮的,函數(shù)返回值與數(shù)據(jù)報首字節(jié)邏輯或后,結(jié)果依然保存在首字節(jié)中。圖29-31列出了鏈傳送的前導字節(jié),其中4位“-”表示正常的IP首部長度字段。7位“C、I、P、S、A、W和E”指明后續(xù)的是哪些可選字段,后面會簡單地介紹這些字母的含 4bit4bit圖29- 圖29-32給出了使用壓縮算法之后,不同類型的完整的IPIPIP數(shù)據(jù)報的頭協(xié)議 0-65515字節(jié)的IP數(shù) 20-60字節(jié)的IP協(xié)議=TCP 20-60字節(jié)的TCP首 0-65495字節(jié)的TCP數(shù)20-60字節(jié)的IP 20-60字節(jié)的TCP首 0-65495字節(jié)的TCP數(shù) 0-65495字節(jié)的TCP 3-16字 協(xié)議=連接TCP非TCP圖29- 采用首部壓縮后的不同類型的IP數(shù)據(jù)圖中給出了兩個IP型數(shù)據(jù)報:一個攜帶了非TCP報文段(如UDP、ICMP或IGMP段),另一個攜帶了TCP報文段。這是為了說明做為IP型數(shù)據(jù)報發(fā)送的TCP報文段與做為PRESSED_TCP型數(shù)據(jù)報發(fā)送的TCP報文段間的差異:前導字節(jié)的4比特互不相同,數(shù)據(jù)報是一個IP分片:分片偏移量非零或者分片標志 、FIN或RST中的任何一個置ACK標志未置位上述3個條件中只要有一個為真,都將作為IP型數(shù)據(jù)此外,即使數(shù)據(jù)報攜帶了可壓縮的TCP報文段,壓縮算法也可能失敗,生成PRESSED_TCP型的數(shù)據(jù)報??赡芤驗楫斍皵?shù)據(jù)報與連接上發(fā)送的上一個數(shù)據(jù)報比較時,有些特殊字段發(fā)生了變化,而正常情況下,對于給定的連接,它們應(yīng)該不變,從而導致壓縮算法無法反映存在的變化。例如,TOS字段,分片標志位。此外,如果某些字段數(shù)值的29-33中給出的IP和TCP的首部字段,陰影字段指對于給定連接,正常情況下不會發(fā)生變化的字段。4- 4-版本4- 4-版本 首部長8-服務(wù)類型16-bit總長(字節(jié)16-bit標識3-標13-bit8-bit存活時間(8-bit協(xié)16-bit32-bit源IP32-bit目的IP16-bit16-bit32-bit序32-bit4-bit首長保留(6UAPPSFRCSSYIGKHTN16-bit16-bitTCP檢驗16-bit20字20字圖29- 組合的IP和TCP首部:陰影字段通常不變?nèi)绻B接上發(fā)送的前一個報文段與當前報文段之間,有陰影字段發(fā)生變化,則壓縮算法失敗,報文段被直接發(fā)送。圖中未列出IP和TCP選項,但如果它們存在,且這些選項字段發(fā)生了變化,則報文段也不壓縮,而被直接發(fā)送(習題29.7)。如果陰影字段均未變化,即使算法只傳輸非陰影字段,也會節(jié)省50%的傳輸容量。VJ首最小的壓縮后的IP/TCP首部只有3個字節(jié):第一個字節(jié)(標志比特),加上16bit的TCP檢驗和。為了防止可能的鏈路錯誤,一般不改動TCP檢驗和(SLIP不提供鏈路層的檢驗和,盡管 16-bitTCP如果U=1:TCP如果W=1:TCP窗口大小差值如果A=1:TCP確認序號差值圖29-34壓縮后的IP/TCP其他的6個字段:connid、urgoff、win、ack、seq和ipid,都是可選的。圖29-34的最左側(cè)列出了各字段壓縮后所需的字節(jié)數(shù)。讀者可能認為壓縮后的首部最大應(yīng)占用19字節(jié),但實際上壓縮后的首部中4bit的SAWU絕不可能同時置位,因此,壓縮首部最大為16字節(jié),后面第一個字節(jié)的最比特必須設(shè)為1,說明這是COMPRESSED_TCP型的數(shù)據(jù)報。其余7bit中的6個規(guī)定了后續(xù)首部中存在哪些可選字段,圖29-35小結(jié)了這7bit的用法。 標志等于0說標志等于1說連接連接ID不connid=連接ipid=IPPSHseq=TCP序號差ack=TCP確認序號差值urgoff=緊急數(shù)據(jù)偏移IPip_id已加TCPPSH標志清TCP序th_seq不TCPth_ack不TCP窗TCPth_win不URG標志未置圖29-35壓縮首部中的7C如果C比特等于0,則當前報文段與前一報文段(無論是壓縮的或非壓縮的)具有相同的 如果I比特等于0,當前報文段的IP標識符較前一報文1(典型情況)。如果等于ipid等于ip_id的當前值減去它的前一P這個比特自TCP報文段中的PSH標志位。因為PSH標志不同于其他的正常方式,S如果S比特等于0,TCP序號不變。如果等于1,seq等于th_seq的當前值減去它的前一個值。A如果A比特等于0,TCP確認序號不變(典型情況)。如果等于1,ack等于th_ack的當前W如果W比特等于0,TCP窗口大小不變。如果等于1,win等于th_win的當前值減去U如果U比特等于0,報文段的URG標志未置位,緊急數(shù)據(jù)偏移量不變(典型情況)等于1URG標志置位,urgoff等于th_urg的當前值。如果URG標志未置位時,緊急數(shù)據(jù)偏移量發(fā)生改變,報文段將被直接發(fā)送(這種現(xiàn)象通常發(fā)生在緊急數(shù)據(jù)傳送完畢后的第一個報文段)。通過字段的當前值減去它的前一個值,得到需傳輸?shù)牟钪怠UG闆r下,得到的是一個小正數(shù)(wi是個例外)。請注意,圖29-34中有5個字段的長度可變,可占用0、1或31字節(jié):發(fā)送值在1~255之間,只需占用13字節(jié):如果發(fā)送值等于0或者在26~6535之間,則需要用3個字節(jié)才能表示:第一個字節(jié)全0,后兩個字節(jié)保存實際值。這種方法一般用于3個16biturgoff、n和ipid。但如果兩個32bi字段ack和eq的差值小于0或者大于6553如果把圖93中不帶陰影的字段與圖94中可能的傳輸字段進行比較,會發(fā)現(xiàn)有些字段IP總長度字段不會被傳輸,因為絕大多數(shù)鏈路層向接收方提供接收數(shù)據(jù)分組的長因為IP首部中被傳輸?shù)奈┮蛔侄问?6bit的IP標識符,IP檢驗和被忽略。因為它只在一算法檢查輸入報文段,如果出現(xiàn)兩種特定情況,則用前導字節(jié)的低位4比特—的兩種特殊組合,分別加以表示。因為緊急數(shù)據(jù)很少出現(xiàn),如果報文段中URG標志置位,并且與前一報文段相比,序號與窗口字段都發(fā)生了變化(意味著低位4比特應(yīng)為1011或1111), 4比特等于1011(稱為*SA)或SA序號與確認序號都增加,差值等于前一報文段的數(shù)據(jù)量,窗口大小與緊急數(shù)據(jù)偏移量不變,URG標志未置位。采用這種表示法可以避免傳送seq和ack。如果對端回送終端數(shù)據(jù),那么兩個傳輸方向上的數(shù)據(jù)報文段中都會經(jīng)常出現(xiàn)這一現(xiàn)象。卷1的圖19-3和圖19-4,舉例說明了登錄應(yīng)用中出現(xiàn)的這種類型的數(shù)據(jù)。S序號增加,差值等于前一報文段的數(shù)據(jù)量,確認序號、窗口大小與緊急數(shù)據(jù)偏移量均不變,URG標志未置位。采用這種表示法可以避免傳送seq。這種類型的數(shù)據(jù)通常出現(xiàn)在單向數(shù)據(jù)傳輸(如FTP)的發(fā)送方。卷1的圖20-1、圖20-和圖20-3舉例說明了這種類型的數(shù)據(jù)傳輸。此外,如果對端不回送終端數(shù)據(jù),那么在數(shù)據(jù)發(fā)送方的數(shù)據(jù)報文段中也會出現(xiàn)這種現(xiàn)象。下面的兩個例子,在圖1-17中的bsdi和slip兩個系統(tǒng)間,利用SLIP鏈路傳輸數(shù)據(jù)。這條SLIP鏈路在兩個傳輸方向上都采用了首部壓縮算法。在主機bsdi上運行tcpdump程序(卷1的附錄A),保存所有數(shù)據(jù)幀的備份。這個程序還支持一個選項,能夠輸出壓縮后的首部,列出圖29-34中的所有字段。在主機間已建立了兩條連接:一條登錄連接,另一條是從bsdi到slip的文件傳(FTP)。圖29-36列出了兩條連接上不同類型數(shù)據(jù)幀出現(xiàn)的次幀類登輸輸輸輸11553223特殊情況00特殊情況119總圖29-36登錄和FTP連接上,不同類型數(shù)據(jù)幀出現(xiàn)的次登錄連接中,在兩個傳輸方向上,*SA都出現(xiàn)了75次,從而證明了在對端回顯終端流量時,這一特定

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論