国产18禁黄网站免费观看,99爱在线精品免费观看,粉嫩metart人体欣赏,99久久99精品久久久久久,6080亚洲人久久精品

2015軟件水平測試:TCP協(xié)議的部分解析(2)

時間:2015-04-07 13:50:00   來源:無憂考網(wǎng)     [字體: ]
端到端意義上的TCP協(xié)議效率

  1.三個問題以及解決

  問題1描述:接收端處理慢,導致接收窗口被填滿

  這明顯是速率不匹配引發(fā)的問題,然而即使速率不匹配,只要滑動窗口能協(xié)調(diào)好它們的速率就好,要快都快,要慢都慢,事實上滑動窗口在這一點上做的很好。但是如果我們不得不從效率上來考慮問題的話,事實就不那么樂觀了?紤]此時接收窗口已然被填滿,慢速的應用程序慢騰騰的讀取了一個字節(jié),空出一個位置,然后通告給TCP的發(fā)送端,發(fā)送端得知空出一個位置,馬上發(fā)出一個字節(jié),又將接收端填滿,然后接收應用程序又一次慢騰騰...這就是糊涂窗口綜合癥,一個大多數(shù)人都很熟悉的詞。這個問題極大的浪費了網(wǎng)絡帶寬,降低了網(wǎng)絡利用率。好比從大同拉100噸煤到北京需要一輛車,拉1Kg煤到北京也需要一輛車(超級夸張的一個例子,請不要相信),但是一輛車開到北京的開銷是一定的...

  問題1解決:窗口通告

  對于問題1,很顯然問題出在接收端,我們沒有辦法限制發(fā)送端不發(fā)送小分段,但是卻可以限制接收端通告小窗口,這是合理的,這并不影響應用程序,此時經(jīng)典的延遲/吞吐量反比律將不再適用,因為接收窗口是滿的,其空出一半空間表示還有一半空間有數(shù)據(jù)沒有被應用讀取,和其空出一個字節(jié)的空間的效果是一樣的,因此可以限制接收端當窗口為0時,直接通告給發(fā)送端以阻止其繼續(xù)發(fā)送數(shù)據(jù),只有當其接收窗口再次達到MSS的一半大小的時候才通告一個不為0的窗口,此前對于所有的發(fā)送端的窗口probe分段(用于探測接收端窗口大小的probe分段,由TCP標準規(guī)定),全部通告窗口為0,這樣發(fā)送端在收到窗口不為0的通告,那么肯定是一個比較大的窗口,因此發(fā)送端可以一次性發(fā)出一個很大的TCP分段,包含大量數(shù)據(jù),也即拉了好幾十噸的煤到北京,而不是只拉了幾公斤。

  即,限制窗口通告時機,解決糊涂窗口綜合癥

  問題2描述:發(fā)送端持續(xù)發(fā)送小包,導致窗口閑置

  這明顯是發(fā)送端引起的問題,此時接收端的窗口開得很大,然而發(fā)送端卻不積累數(shù)據(jù),還是一味的發(fā)送小塊數(shù)據(jù)分段。只要發(fā)送了任和的分段,接收端都要無條件接收并且確認,這完全符合TCP規(guī)范,因此必然要限制發(fā)送端不發(fā)送這樣的小分段。

  問題2解決:Nagle算法

  Nagel算法很簡單,標準的Nagle算法為:

  IF 數(shù)據(jù)的大小和窗口的大小都超過了MSS

  Then 發(fā)送數(shù)據(jù)分段

  ELSE

  IF 還有發(fā)出的TCP分段的確認沒有到來

  Then 積累數(shù)據(jù)到發(fā)送隊列的末尾的TCP分段

  ELSE

  發(fā)送數(shù)據(jù)分段

  EndIF

  EndIF

  可是后來,這個算法變了,變得更加靈活了,其中的:

  IF 還有發(fā)出的TCP分段的確認沒有到來

  變成了

  IF 還有發(fā)出的不足MSS大小的TCP分段的確認沒有到來

  這樣如果發(fā)出了一個MSS大小的分段還沒有被確認,后面也是可以隨時發(fā)送一個小分段的,這個改進降低了算法對延遲時間的影響。這個算法體現(xiàn)了一種自適應的策略,越是確認的快,越是發(fā)送的快,雖然Nagle算法看起來在積累數(shù)據(jù)增加吞吐量的同時也加大的時延,可事實上,如果對于類似交互式的應用,時延并不會增加,因為這類應用回復數(shù)據(jù)也是很快的,比如Telnet之類的服務必然需要回顯字符,因此能和對端進行自適應協(xié)調(diào)。

  注意,Nagle算法是默認開啟的,但是卻可以關閉。如果在開啟的情況下,那么它就嚴格按照上述的算法來執(zhí)行。

  問題3.確認號(ACK)本身就是不含數(shù)據(jù)的分段,因此大量的確認號消耗了大量的帶寬

  這是TCP為了確?煽啃詡鬏?shù)囊?guī)范,然而大多數(shù)情況下,ACK還是可以和數(shù)據(jù)一起捎帶傳輸?shù)。如果沒有捎帶傳輸,那么就只能單獨回來一個ACK,如果這樣的分段太多,網(wǎng)絡的利用率就會下降。從大同用火車拉到北京100噸煤,為了確認煤已收到,北京需要派一輛同樣的火車空載開到大同去復命,因為沒有別的交通工具,只有火車。如果這位復命者剛開著一列火車走,又從大同來了一車煤,這拉煤的哥們兒又要開一列空車去復命了。

  問題3的解決:

  RFC 建議了一種延遲的ACK,也就是說,ACK在收到數(shù)據(jù)后并不馬上回復,而是延遲一段可以接受的時間,延遲一段時間的目的是看能不能和接收方要發(fā)給發(fā)送方的數(shù)據(jù)一起回去,因為TCP協(xié)議頭中總是包含確認號的,如果能的話,就將ACK一起捎帶回去,這樣網(wǎng)絡利用率就提高了。往大同復命的確認者不必開一輛空載火車回大同了,此時北京正好有一批貨物要送往大同,這位復命者搭著這批貨的火車返回大同。

  如果等了一段可以接受的時間,還是沒有數(shù)據(jù)要發(fā)往發(fā)送端,此時就需要單獨發(fā)送一個ACK了,然而即使如此,這個延遲的ACK雖然沒有等到可以被捎帶的數(shù)據(jù)分段,也可能等到了后續(xù)到來的TCP分段,這樣它們就可以取者一起返回了,要知道,TCP的確認號是收到的按序報文的最后一個字節(jié)的后一個字節(jié)。最后,RFC建議,延遲的ACK最多等待兩個分段的積累確認。

  2.分析三個問題之間的關聯(lián)

  三個問題導致的結(jié)果是相同的,但是要知道它們的原因本質(zhì)上是不同的,問題1幾乎總是出現(xiàn)在接收端窗口滿的情況下,而問題2幾乎總是發(fā)生在窗口閑置的情況下,問題3看起來是最無聊的,然而由于TCP的要求,必須要有確認號,而且一個確認號就需要一個TCP分段,這個分段不含數(shù)據(jù),無疑是很小的。

  三個問題都導致了網(wǎng)絡利用率的降低。雖然兩個問題導致了同樣的結(jié)果,但是必須認識到它們是不同的問題,很自然的將這些問題的解決方案匯總在一起,形成一個全局的解決方案,這就是如今的操作系統(tǒng)中的解決方案。

  3.問題的雜糅情況

  疑難雜癥11:糊涂窗口解決方案和Nagle算法

  糊涂窗口綜合癥患者希望發(fā)送端積累TCP分段,而Nagle算法確實保證了一定的TCP分段在發(fā)送端的積累,另外在延遲ACK的延遲的那一會時間,發(fā)送端會利用這段時間積累數(shù)據(jù)。然而這卻是三個不同的問題。Nagle算法可以緩解糊涂窗口綜合癥,卻不是治本的良藥。

  疑難雜癥12:Nagle算法和延遲ACK

  延遲ACK會延長ACK到達發(fā)送端的時間,由于標準Nagle算法只允許一個未被確認的TCP分段,那無疑在接收端,這個延遲的ACK是毫無希望等待后續(xù)數(shù)據(jù)到來最終進行積累確認的,如果沒有數(shù)據(jù)可以捎帶這個ACK,那么這個ACK只有在延遲確認定時器超時的時候才會發(fā)出,這樣在等待這個ACK的過程中,發(fā)送端又積累了一些數(shù)據(jù),因此延遲ACK實際上是在增加延遲的代價下加強了Nagle算法。在延遲ACK加Nagle算法的情況下,接收端只有不斷有數(shù)據(jù)要發(fā)回,才能同時既保證了發(fā)送端的分段積累,又保證了延遲不增加,同時還沒有或者很少有空載的ACK。

  要知道,延遲ACK和Nagle是兩個問題的解決方案。

  疑難雜癥13:到底何時可以發(fā)送數(shù)據(jù)

  到底何時才能發(fā)送數(shù)據(jù)呢?如果單從Nagle算法上看,很簡單,然而事實證明,情況還要更復雜些。如果發(fā)送端已經(jīng)排列了3個TCP分段,分段1,分段2,分段3依次被排入,三個分段都是小分段(不符合Nagle算法中立即發(fā)送的標準),此時已經(jīng)有一個分段被發(fā)出了,且其確認還沒有到來,請問此時能發(fā)送分段1 和2嗎?如果按照Nagle算法,是不能發(fā)送的,但實際上它們是可以發(fā)送的,因為這兩個分段已經(jīng)沒有任何機會再積累新的數(shù)據(jù)了,新的數(shù)據(jù)肯定都積累在分段 3上了。問題在于,分段還沒有積累到一定大小時,怎么還可以產(chǎn)生新的分段?這是可能的,但這是另一個問題,在此不談。

  Linux的TCP實現(xiàn)在這個問題上表現(xiàn)的更加靈活,它是這么判斷能否發(fā)送的(在開啟了Nagle的情況下):

  IF (沒有超過擁塞窗口大小的數(shù)據(jù)分段未確認 || 數(shù)據(jù)分段中包含F(xiàn)IN ) &&

  數(shù)據(jù)分段沒有超越窗口邊界

  Then

  IF 分段在中間(上述例子中的分段1和2) ||

  分段是緊急模式 ||

  通過上述的Nagle算法(改進后的Nagle算法)

  Then 發(fā)送分段

  EndIF

  EndIF

  曾經(jīng)我也改過Nagle算法,確切的說不是修改Nagle算法,而是修改了“到底何時能發(fā)送數(shù)據(jù)”的策略,以往都是發(fā)送端判斷能否發(fā)送數(shù)據(jù)的,可是如果此時有延遲ACK在等待被捎帶,而待發(fā)送的數(shù)據(jù)又由于積累不夠或者其它原因不能發(fā)送,因此兩邊都在等,這其實在某些情況下不是很好。我所做的改進中對待何時能發(fā)送數(shù)據(jù)又增加了一種情況,這就是“ACK拉”的情況,一旦有延遲ACK等待發(fā)送,判斷一下有沒有數(shù)據(jù)也在等待發(fā)送,如果有的話,看看數(shù)據(jù)是否大到了一定程度,在此,我選擇的是MSS的一半:

  IF (沒有超過擁塞窗口大小的數(shù)據(jù)分段未確認 || 數(shù)據(jù)分段中包含F(xiàn)IN ) &&

  數(shù)據(jù)分段沒有超越窗口邊界

  Then

  IF 分段在中間(上述例子中的分段1和2) ||

  分段是緊急模式 ||

  通過上述的Nagle算法(改進后的Nagle算法)

  Then 發(fā)送分段

  EndIF

  ELSE IF 有延遲ACK等待傳輸 &&

  發(fā)送隊列中有待發(fā)送的TCP分段 &&

  發(fā)送隊列的頭分段大小大于MSS的一半

  Then 發(fā)送隊列頭分段且捎帶延遲ACK

  EndIF

  另外,發(fā)送隊列頭分段的大小是可以在統(tǒng)計意義上動態(tài)計算的,也不一定非要是MSS大小的一半。我們發(fā)現(xiàn),這種算法對于交互式網(wǎng)路應用是自適應的,你打字越快,特定時間內(nèi)積累的分段就越長,對端回復的越快(可以捎帶ACK),本端發(fā)送的也就越快(以Echo舉例會更好理解)。

  疑難雜癥14:《TCP/IP詳解(卷一)》中Nagle算法的例子解讀

  這個問題在網(wǎng)上搜了很多的答案,有的說RFC的建議,有的說別的。可是實際上這就是一個典型的“競態(tài)問題”:

  首先服務器發(fā)了兩個分段:

  數(shù)據(jù)段12:ack 14

  數(shù)據(jù)段13:ack 14,54:56

  然后客戶端發(fā)了兩個分段:

  數(shù)據(jù)段14:ack 54,14:17

  數(shù)據(jù)段15:ack 56,17:18

  可以看到數(shù)據(jù)段14本來應該確認56的,但是確認的卻是54。也就是說,數(shù)據(jù)段已經(jīng)移出隊列將要發(fā)送但還未發(fā)送的時候,數(shù)據(jù)段13才到來,軟中斷處理程序搶占了數(shù)據(jù)段14的發(fā)送進程,要知道此時只是把數(shù)據(jù)段14移出了隊列,還沒有更新任何的狀態(tài)信息,比如“發(fā)出但未被確認的分段數(shù)量”,此時軟中斷處理程序順利接收了分段13,然后更新窗口信息,并且檢查看有沒有數(shù)據(jù)要發(fā)送,由于分段14已經(jīng)移出隊列,下一個接受發(fā)送檢查的就是分段15了,由于狀態(tài)信息還沒有更新,因此分段15順利通過發(fā)送檢測,發(fā)送完成。

  可以看Linux的源代碼了解相關信息,tcp_write_xmit這個函數(shù)在兩個地方會被調(diào)用,一個是TCP的發(fā)送進程中,另一個就是軟中斷的接收處理中,兩者在調(diào)用中的競態(tài)就會引起《詳解》中的那種情況。注意,這種不加鎖的發(fā)送方式是合理的,也是效的,因此TCP的處理語義會做出判斷,丟棄一切不該接收或者重復接收的分段的。