在前篇文章中介紹了TCP協議的三大特性,其中可靠性是依賴一系列的機制,如:校驗和,分組發送,超時重傳,流量控制獲得保證。算法
TCP在交互數據時,採用多種機制保證可靠性,同時也保證TCP的性能,主要是分組、延遲ACK等等。服務器
對於連續的數據傳輸有三種方式:網絡
顯然前兩種方式都是比較極端,單個單個字節發送對於成塊連續數據而言效率很是低,整塊連續數據發送對於比較大的數據而言更不現實,TCP緩衝區有限,網絡帶框也是有限,對於過大數據不可能這樣發送。tcp
在TCP協議棧中,有發送緩衝區和接收緩衝區用於緩衝存儲即將發送的數據和收到的數據。當應用須要發送連續數據時,TCP將應用的數據存儲到緩衝區中,TCP會根據必定的機制將緩衝區數據發送出去,應用同時也將數據寫入緩衝區。接收方TCP在收到數據後,存入接收緩衝區中,TCP根據必定機制再將緩衝區中數據提交給應用處理。性能
TCP將成塊的數據發送分紅一個個的分組報文發送出去,其中分組報文大小不會超過MSS(Max Segment Size,最大的報文段大小)。TCP對發送的每一個字節都採用序號的方式進行標識追蹤,序號在創建TCP鏈接時即已經肯定。發送端發送第一個字節數據的序號爲創建TCP鏈接時的SEQ + 1。序號在這裏有如下幾種做用:大數據
標識發送數據的起始序號爲TCP報文中的序號,沒增長一個字節序號就增長1,因此發送的下個TCP報文的序號爲上一個序號加上個報文的大小。經過這種方式TCP能夠表示每一個已經發送的每一個字節。設計
對成塊連續數據分組發送的方式,會帶來不少問題,好比發送方如何確認接收方已經收到數據?3d
TCP採用ACK確認機制解決該問題,接收方在接受到數據後,必需要回復一個ACK的確認包告訴發送方已經收到該報文。其中有個確認序號,標識期待下次接收到的數據的起始序號。這個ACK的確認序號就是TCP報文段中的確認序號。blog
看到這個機制,對於瞭解消息MQ讀者應該能聯想到MQ是如何解決消息丟失的問題。能夠說MQ的消息回執確認機制也正式來源於TCP的這個機制。上層不少設計都是來源於底層的設計思想。排序
經過確認機制能夠保證報文丟失時,發送方可以感知到,這一點也是TCP的可靠性保證之一。
從以上圖中,能夠看到客戶端發送的報文都有相應的確認報文用於通知客戶端服務器端已經接收到。分組發送,ACK確認機制是TCP可靠性保證的機制之一。
大多數客戶服務器之間的通訊都是雙方向的數據流動,在這種狀況下若是是客戶端應用請求TCP發送數據,而後服務端的TCP回覆ACK確認,而後服務端TCP再發送應用層的響應值客戶端,客戶端再發送ACK。這樣來回須要四次,無疑增長網絡負擔,使得網絡擁塞。爲了提高TCP的性能,儘量的減少網絡負擔,延遲ACK策略決定接收端TCP在接手到發送方的數據後,不當即回覆ACK,而是通過一個ACK的延遲時間段後再回復ACK。若是這個時間段內有數據須要發送,則放在緩衝區,而後將ACK和這個數據發送做爲一個報文段發給發送方。
通常這個延遲的時間是200ms,能夠看出,TCP是重複利用網絡資源,重複利用TCP數據報,達到最大化的網絡傳輸。
從上圖能夠看出,每一個PSH包都會使捎帶ACK的,這樣將本來可能須要四次交互減低到只要兩次。
前面提到TCP有發送緩衝區,在發送時,應用的數據被內核寫入該緩衝區後,TCP再發出去。分組發送時,若是是很是多的微小的分組數據包被不斷髮出去,則有可能形成網絡擁塞,特別是在廣域網上。
Nagle算法要求在一個TCP鏈接上最多隻有一個未確認的分組,在該分組的確認包到達以前,發送將不能在發送其餘的分組。應用層須要發的數據都被存在緩衝區,待收到確認包後,將緩衝區中的數據一塊發送出去。該算法旨在解決大量的微小分組在低速帶寬上頻繁發送可能形成網絡擁塞的問題。
若是更加直接的說,Nagle算法便是將發送的積累沉澱,知道達到必定的條件後再做爲大的分組發送,避免大量微小分組形成網絡擁塞。這個條件是:
知足以上條件之一,將才會發送緩衝區的數據。
Nagle算法旨在解決大量微小分組形成的擁塞問題,可是若是在帶寬較大且網絡負載不大的局域網上,且應用對延遲很是敏感的時,Nagle算法則不合適。由於應用須要發送的數據被緩衝,未被髮出而獲得響應,產生延遲。
特別當Nagle算法遇到ACK延遲,二者共同做用時,該狀況尤其明顯。由於一個TCP鏈接上只存在一個未確認的分組,且該分組又被ACK延遲。二者共同做用,帶來更大的延遲。對於延遲敏感應用則加重這種狀況。
對於大多數局域網內的應用交互,能夠經過設置TCP鏈接套接字,禁用Nagle算法。讓一個鏈接上能夠存在多個未確認分組,能夠連續發屢次分組,從而下降延遲。可是對於在廣域網上因爲流量較大和RRT較長緣由,禁用Nagle算法不只可能會形成網絡擁塞,並且產生的網絡延遲可能更嚴重。
Socket套接字提供應用層Socket參數TCP_NODELAY參數用於開啓和關閉Nagle算法。能夠經過Java的API瞭解:
發送端經過Nagle算法累積發送數據,從而避免大量微小分組出如今網絡中。從而發送一個較大分組,解決擁塞和必定的延遲問題。接收端若是對接收到的每一個報文段都進行ACK,那麼網絡中將存在大量的ACK包,從而加劇網絡負載。
TCP設計ACK累積策略,該策略並非針對每一個TCP報文都須要進行ACK確認。接收端的TCP建立一個針對發送端IP的隊列,接收到的報文都進入該隊列。接收到TCP報文段後,啓動延遲ACK定時器。在該定時時間段內,仍然會接收發送過來的數據進入隊列。在必定條件下,而後回覆已經收到的最大的數據SEQ + 1做爲ACK回覆確認序號。以下通訊過程:
從上圖能夠看出,當svr和bsdi在創建鏈接後,svr連續發送了三個TCP報文,可是bsdi並非對每一個報文都進行了ACK,當序號爲1的PSH包到達後,bsdi的TCP啓動延遲ACK,而後又接收到了1025序號的TCP報文,此時有兩個未確認的報文,因此發送了一個2049的ACK。當接收方收到2049的ACK後,即知道前面一個序號爲1的報文也已經接收到了,否則接收端是不會回覆2049的ACK的。
經過ACK累積,能夠減小ACK包,從而提高網絡利用率,下降擁塞的可能。
TCP的可靠性另外一方面的保證機制即超時重傳。上節說到經過ACK的方式讓發送方知道接收方是否收到了數據。可是數據和ACK包都有可能會丟,即便接收方收到了,可是ACK卻丟失。那樣對於發送方而言,仍然不知道接受方是否接受到了數據。
TCP協議設計超時重傳機制。發送方的TCP在發送TCP報文後,針對該報文啓動重傳定時器,若是當定時器溢出超時後,仍然沒有收到該報文的ACK,則從新發送該報文。而後再啓動相應的定時器等待ACK,直到發送成功或者重發必定次數失敗後。
如下客戶單經過telnet程序演示TCP的超時重傳機制的過程。
發送端發送"hello2."時因爲網絡鏈接斷開,而後重複發送。經過tcpdump能夠看出