在計算機網絡的世界中,大量的數據經由信道進行傳輸,通訊信道是不可靠,不安全的,可是不少時候咱們又但願咱們可以可靠的收發數據。那麼是否是能夠設計一種通訊協議來保證數據的可靠性呢?緩存
答案固然是能夠的。下面咱們就一步步來探究如何實現一個可靠的通訊協議(如下用rdt簡稱):安全
rdt1.0:在最開始的版本咱們假設信道是徹底可靠的,也就是說信道不會發生錯誤,也不會丟棄分組。服務器
那麼在這種狀況下,因爲咱們肯定信道是可靠的,因此咱們不須要作任何處理,只須要發送方發送,接收方接收就徹底OK了。網絡
rdt2.0:此時假設信道可能會發生位錯誤,可是全部的報文段都是按序到達的,而且不會在傳輸過程當中丟失。性能
這裏有兩個問題須要解決:怎麼判斷接收到的數據是錯誤的?若是接收到了錯誤的數據,應該如何從錯誤中恢復?計算機網絡
先來解決第一個問題:數據在組裝的時候,咱們能夠在報文段中加入校驗和,這樣接收方就能夠根據這個校驗和判斷接收到的數據是否發生了錯誤。設計
如今解決第二個問題:如今接收方接收到了一個錯誤的報文,那麼對於接收方來講,很容易,直接把錯誤的報文丟棄就好。但問題是發送方並不知道發送的報文在傳輸過程當中出錯了。要解決這個問題,咱們就要加入新的消息機制。也就是說當接收方接收到了一個正確的報文段的時候,接收方給發送方回一個消息(ACK),確認我收到了正確的報文,能夠繼續發送。若是收到了錯誤的報文,就發一個NAK表示報文出錯,須要發送方重傳一個報文。htm
rdt2.1:在rdt2.0中咱們加入了ACK/NAK機制來避免錯誤,那麼若是ACK或者NAK錯了怎麼辦?發送方沒有收到接收方的正確消息就會一直等待,此時會出現死鎖。blog
這時能夠想到的一個方法就是發送方若是收到錯誤的ACK/NAK就重傳,可是可能會致使重複的分組。那麼解決方法就是給每一個報文加入序列號。get
發送方描述:發送序列號爲0的分組,等待確認消息。若是收到ACK,發送序列號爲1的分組;若是收到NAK或者錯誤的ACK/NAK,重傳序列號爲0的分組。
接收方描述:若是收到正確序列號爲0的分組發送ACK,錯誤就發送NAK,若是指望收到序列號爲0的分組卻收到了序列號爲1的分組,發送ACK。
rdt2.2:在rdt2.1中咱們使用了ACK/NAK來做爲消息傳遞機制,那麼有沒有可能咱們只用一個消息好比只用ACK來做爲確認機制呢?答案固然是能夠的,咱們能夠在ACK中加入已經確認正確接收的序列號就行。
rdt3.0:在以前的協議中,咱們都是假設信道只會發生位錯誤,不會丟失。如今把這個限制去掉,數據在發送的過程當中可能會丟失。
基於上面的條件,前面的協議就可能會致使死鎖(ACK丟失)。爲了不死鎖,咱們須要加入超時機制。也就是說當發送方等待必定的時間沒有收到接收方的ACK的時候,就重傳數據。
經過以上的協議設計,咱們已經基本可以保證通訊的可靠性了。可是咱們以前的協議都是基於停——等協議的(即發送數據,等待回執消息ACK),此時等待時間若是遠遠大於數據發送的時間,這個協議的效率是很低。rdt3.0也是如此,它的性能是不好的。致使rdt性能比較差的緣由是咱們使用了停等協議,一個很容易想到的改進方法就是使用流水線協議。即一次發送幾個分組,而不是一個只發送一個分組,由此推出了滑動窗口協議。
什麼是滑動窗口?看下面的一個圖:
滑動窗口顧名思義,能夠滑動的一個窗口。其實這就是發送方規定了一個大小固定的發送數據段,只有在這個窗口內的數據幀才容許發送。
滑動窗口分爲兩種:分別是GBN和SR。
GBN:GBN只有發送方有滑動窗口,接收方沒有。發送方發送數據幀後,等待回執消息。若是收到ACK(採用累計確認),則確認已收到的數據幀,窗口向前滑動,繼續發送數據幀。若是超時就重發全部未確認的數據幀(如圖d是3和4)。接收方收到數據幀採用累計確認,若是收到亂序數據直接丟棄。例如收到0132四個數據幀,32直接丟棄,ACK確認1(累計確認)。
SR:SR協議發送方和接收方都有滑動窗口。相比於GBN,SR單獨確認每一個分組。接收方對於亂序分組先緩存,單獨回執接收到的分組。同時爲每一個分組設置計時器。這樣發送方就不須要像GBN同樣,只須要重傳未收到的分組就行了。
TCP的可靠數據傳輸:
TCP做爲一個可靠數據傳輸協議,它都用了那些原理來保證可靠數據傳輸呢?
TCP協議使用的是滑動窗口,可是TCP既不是徹底的GBN也不是徹底的SR。TCP是爲每一分組都單獨設置定時器,並且採用的是累計確認。
爲了保證TCP傳輸的性能,TCP的計時器=RTT平均值+「安全邊界」。因爲採用了這種機制,當出現超時狀況時,超時時間間隔將加倍,這樣就會致使超時時間過長。爲了解決這個問題,TCP加入快速重傳機制,即在超時發生以前,若是收到同一數據的三次ACK就觸發重傳。
TCP的流量控制:
接收方的接收buffer區大小有限,若是發送速度太快,而讀取速度較小可能會致使buffer溢出。接收方會在報文首部加上一個RecWindow,告訴發送方還能夠接收多少數據。這裏會出現一個問題,若是發送方收到RecWindow==0的消息,該怎麼辦,一直等(死鎖)固然不行。因此即便RecWindow爲0的時候,發送方仍能夠發送小段數據試探,直到接收方可以接收數據爲止。
TCP的鏈接管理:
三次握手創建鏈接,四次揮手關閉鏈接。前一篇已經講過,就不贅述。這裏須要注意的是:client收到服務器發送的FIN,並向服務器發送ACK後會設置計時器,若是再次收到FIN就重發ACK,確保服務器已經關閉。
TCP的擁塞控制:
兩種擁塞控制方法:AIMD(加性增,乘性減)和SS(慢啓動)。
AIMD:發送速度一開始每次加一樣的速度,當發生擁塞時,直接把速度減半。
SS:一開始速度很小,以後採用指數增加。