TCP/IP協議淺析二
來自專欄一起來coding
可靠數據傳輸
在計算機網路的世界中,大量的數據經由信道進行傳輸,通信信道是不可靠,不安全的,但是很多時候我們又希望我們能夠可靠的收發數據。那麼是不是可以設計一種通信協議來保證數據的可靠性呢?
答案當然是可以的。下面我們就一步步來探究如何實現一個可靠的通信協議(以下用rdt簡稱):
rdt1.0:在最開始的版本我們假設信道是完全可靠的,也就是說信道不會發生錯誤,也不會丟棄分組。
那麼在這種情況下,由於我們確定信道是可靠的,所以我們不需要做任何處理,只需要發送方發送,接收方接收就完全OK了。
rdt2.0:此時假設信道可能會發生位錯誤,但是所有的報文段都是按序到達的,並且不會在傳輸過程中丟失。
這裡有兩個問題需要解決:怎麼判斷接收到的數據是錯誤的?如果接收到了錯誤的數據,應該如何從錯誤中恢復?
先來解決第一個問題:數據在組裝的時候,我們可以在報文段中加入校驗和,這樣接收方就可以根據這個校驗和判斷接收到的數據是否發生了錯誤。
現在解決第二個問題:現在接收方接收到了一個錯誤的報文,那麼對於接收方來說,很容易,直接把錯誤的報文丟棄就好。但問題是發送方並不知道發送的報文在傳輸過程中出錯了。要解決這個問題,我們就要加入新的消息機制。也就是說當接收方接收到了一個正確的報文段的時候,接收方給發送方回一個消息(ACK),確認我收到了正確的報文,可以繼續發送。如果收到了錯誤的報文,就發一個NAK表示報文出錯,需要發送方重傳一個報文。
rdt2.1:在rdt2.0中我們加入了ACK/NAK機制來避免錯誤,那麼如果ACK或者NAK錯了怎麼辦?發送方沒有收到接收方的正確消息就會一直等待,此時會出現死鎖。
這時可以想到的一個方法就是發送方如果收到錯誤的ACK/NAK就重傳,但是可能會導致重複的分組。那麼解決方法就是給每個報文加入序列號。
發送方描述:發送序列號為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協議使用的是滑動窗口,但是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:一開始速度很小,之後採用指數增長。
推薦閱讀:
※TCP/IP協議原理與介紹
※(四)智能家居系統組成及協議介紹
※為什麼新開發的可靠傳輸協議都是基於UDP協議?
※超有趣學網路-第2節 OSI和TCP/IP-1
※IPsec