tcp 如何保證可靠性
大家都知道TCP是可靠性傳輸協(xié)議,既然是可靠的,就需要解決比如包丟失了、數(shù)據(jù)被破壞了、包重復(fù)了、亂序了等等這樣的問題。下面將從幾個(gè)方面介紹TCP的可靠性。
1. 校驗(yàn)和
TCP每一段報(bào)文都有校驗(yàn)和,這保證了報(bào)文不被破壞或篡改,如果收到的報(bào)文在校驗(yàn)過程中有差錯(cuò),TCP 將丟棄這個(gè)報(bào)文段和不確認(rèn)收到此報(bào)文段。
2.序列號(hào)與確認(rèn)應(yīng)答
TCP發(fā)送的每一個(gè)包都有一個(gè)序列號(hào),這可以讓接收方知道自己已經(jīng)接收到了那些包,哪些包丟失了,重復(fù)的包也可以根據(jù)序號(hào)丟棄,并且根據(jù)序號(hào)將包排序,同時(shí)每一個(gè)發(fā)送的包都會(huì)返回一個(gè)確認(rèn)應(yīng)答消息,來確保消息被接收。
3.重傳機(jī)制
TCP 實(shí)現(xiàn)可靠傳輸?shù)姆绞街?,是通過序列號(hào)與確認(rèn)應(yīng)答,當(dāng)發(fā)送端的數(shù)據(jù)到達(dá)接收主機(jī)時(shí),接收端主機(jī)會(huì)返回一個(gè)確認(rèn)應(yīng)答消息,表示已收到消息,如果數(shù)據(jù)包丟失了,就會(huì)用重傳機(jī)制解決。
重傳機(jī)制分為超時(shí)重傳、快速重傳、SACK、D-SACK
-
超時(shí)重傳 :在發(fā)送數(shù)據(jù)時(shí),設(shè)定一個(gè)定時(shí)器,當(dāng)超過指定的時(shí)間后,沒有收到對(duì)方的 ACK 確認(rèn)應(yīng)答報(bào)文,就會(huì)重發(fā)該數(shù)據(jù)。超時(shí)時(shí)間被稱為RTO,一般略大于RTT,不過RTO是一個(gè)動(dòng)態(tài)值,具體如何計(jì)算,有興趣的可以自行查詢。如果重傳的包又超時(shí)了,那么再次重傳時(shí)間隔為上一次代分倍數(shù);即每當(dāng)遇到一次超時(shí)重傳的時(shí)候,都會(huì)將下一次超時(shí)時(shí)間間隔設(shè)為先前值的兩倍。兩次超時(shí),就說明網(wǎng)絡(luò)環(huán)境差,不宜頻繁反復(fù)發(fā)送。
-
快速重傳 :超時(shí)重傳的問題是要等超時(shí)時(shí)間后才會(huì)重傳??焖僦貍鞑灰詴r(shí)間為驅(qū)動(dòng),而是以數(shù)據(jù)驅(qū)動(dòng)重傳,服務(wù)器如果收到亂序的包,也給客戶端回復(fù) ACK,比如收到亂序的包 6,7,8,9 時(shí),服務(wù)器全都發(fā) ACK = 5,這樣客戶端就知道5丟失了,當(dāng)客戶端收到三個(gè)相同的 ACK 報(bào)文時(shí),會(huì)在超時(shí)之前,重傳丟失的報(bào)文段,而不需要等到計(jì)時(shí)器超時(shí)。
-
SACK 選擇性確認(rèn) :快速重傳只解決了超時(shí)時(shí)間的問題,假如有19個(gè)包要傳,其中4和5丟失了,服務(wù)端收到了69的包后,都只給客戶端響應(yīng)缺少4,客戶端這時(shí)有兩種選擇:1.重傳單個(gè)包,這個(gè)時(shí)候只會(huì)重傳4,再次等到三個(gè)ACK后才會(huì)重傳5,這樣效率就會(huì)很低;2.重傳4之后的所有包,由于服務(wù)端已經(jīng)收到6~9,重傳一次就會(huì)造成資源的浪費(fèi)。于是就有了選擇性確認(rèn)這種機(jī)制,這種方式需要在 TCP 頭部 選項(xiàng)(在上一章節(jié)的TCP頭部報(bào)文格式中有介紹) 字段里加一個(gè) SACK 的選項(xiàng),它可以將已收到的數(shù)據(jù)的信息發(fā)送給「發(fā)送方」,這樣發(fā)送方就可以知道哪些數(shù)據(jù)收到了,哪些數(shù)據(jù)沒收到,知道了這些信息,就可以只重傳丟失的數(shù)據(jù)
4.滑動(dòng)窗口
TCP 是每發(fā)送一個(gè)數(shù)據(jù),就需要等待對(duì)方進(jìn)行ACK確認(rèn)應(yīng)答,這顯然會(huì)極大的影響傳輸?shù)乃俾?。在發(fā)送數(shù)據(jù)的時(shí)候,最好的方式是一下將所有的數(shù)據(jù)全部發(fā)送出去,然后一起確認(rèn)。于是就引入了窗口的概念,這個(gè)所謂的窗口實(shí)際上是操作系統(tǒng)開辟的一個(gè)緩存空間,發(fā)送方在等到確認(rèn)應(yīng)答返回之前,必須在緩沖區(qū)中保留已發(fā)送的數(shù)據(jù)。如果按期收到確認(rèn)應(yīng)答后,此時(shí)數(shù)據(jù)就可以從緩存區(qū)清除,同樣接收方接收數(shù)據(jù)后也是放在這個(gè)緩存區(qū)中的,那么接收方緩存區(qū)還能接收多少數(shù)據(jù),這個(gè)就是決定窗口大小的因素,如果發(fā)送方的數(shù)據(jù)超過接收方緩存區(qū)的大小,那會(huì)造成接收方數(shù)據(jù)溢出,這就會(huì)導(dǎo)致數(shù)據(jù)丟失。所以,通常窗口的大小是由接收方的窗口大小來決定的。發(fā)送方發(fā)送的數(shù)據(jù)大小不能超過接收方的窗口大小,否則接收方就無法正常接收到數(shù)據(jù)。
發(fā)送方的滑動(dòng)窗口
- 1是已發(fā)送并收到 ACK確認(rèn)的數(shù)據(jù)
- 2是已發(fā)送但未收到 ACK確認(rèn)的數(shù)據(jù)
- 3是允許發(fā)送但尚未發(fā)送的數(shù)據(jù),總大小在接收方處理范圍內(nèi)
- 4是不允許發(fā)送的數(shù)據(jù),總大小超過接收方處理范圍
滑動(dòng)窗口并不是固定的,它主要是根據(jù)接收方的接收情況,動(dòng)態(tài)去調(diào)整窗口大小,然后來控制發(fā)送方的數(shù)據(jù)流量
零窗口
在接收方窗口大小變?yōu)?的時(shí)候,發(fā)送方就不能再發(fā)送數(shù)據(jù)了。但是當(dāng)接收方窗口恢復(fù)的時(shí)候發(fā)送方要怎么知道那?在這個(gè)時(shí)候TCP會(huì)啟動(dòng)一個(gè)零窗口(TCP Zero Window)定時(shí)探測(cè)器,向接收方詢問窗口大小,當(dāng)接收方窗口恢復(fù)的時(shí)候,就可以再次發(fā)送數(shù)據(jù)
流量控制
發(fā)送方不能無限制的發(fā)數(shù)據(jù)給接收方,也要考慮接收方的處理能力,如果一直無限制的發(fā)數(shù)據(jù)給對(duì)方,但對(duì)方處理不過來,那么就會(huì)導(dǎo)致觸發(fā)重發(fā)機(jī)制,從而導(dǎo)致網(wǎng)絡(luò)流量的無端的浪費(fèi)。為了解決這種現(xiàn)象發(fā)生,TCP 提供一種機(jī)制可以讓「發(fā)送方」根據(jù)「接收方」的實(shí)際接收能力控制發(fā)送的數(shù)據(jù)量,這就是所謂的流量控制。流量控制由滑動(dòng)窗口協(xié)議實(shí)現(xiàn),滑動(dòng)窗口既保證了分組無差錯(cuò)、有序接收,也實(shí)現(xiàn)了流量控制。主要的方式就是接收方返回的 ACK 中會(huì)包含自己的接收窗口的大小,并且利用大小來控制發(fā)送方的數(shù)據(jù)發(fā)送。
擁塞控制
有了流量控制為什么還需要擁塞控制?
流量控制:流量控制是針對(duì)接收者的,它是控制發(fā)送者的發(fā)送速度從而使接收者來得及接收,防止分組丟失的。即防止發(fā)送方的數(shù)據(jù)填滿接收方的緩存區(qū)。
擁塞控制:擁塞控制是作用于網(wǎng)絡(luò)的,它是防止過多的數(shù)據(jù)注入到網(wǎng)絡(luò)中,避免出現(xiàn)網(wǎng)絡(luò)負(fù)載過大的情況。即防止發(fā)送方的數(shù)據(jù)填滿整個(gè)網(wǎng)絡(luò)
在網(wǎng)絡(luò)出現(xiàn)擁堵時(shí)減少數(shù)據(jù)包的發(fā)送,網(wǎng)絡(luò)恢復(fù)后它又會(huì)增加數(shù)據(jù)包的發(fā)送,這就是擁塞控制。
擁塞窗口cwnd:是發(fā)送方維護(hù)的一個(gè)的狀態(tài)變量,它會(huì)根據(jù)網(wǎng)絡(luò)的擁塞程度動(dòng)態(tài)變化的,只要網(wǎng)絡(luò)中沒有出現(xiàn)擁塞,擁塞窗口就會(huì)變大,當(dāng)網(wǎng)絡(luò)中出現(xiàn)了擁塞它就會(huì)變小。
如何知道網(wǎng)絡(luò)擁塞?
只要發(fā)送方?jīng)]有在規(guī)定時(shí)間內(nèi)接收到 ACK 應(yīng)答報(bào)文,也就是發(fā)生了超時(shí)重傳,就會(huì)認(rèn)為網(wǎng)絡(luò)出現(xiàn)了擁塞。
擁塞控制算法:
-
慢啟動(dòng):TCP 在剛建立連接完成后并不知道網(wǎng)絡(luò)情況,它會(huì)一點(diǎn)一點(diǎn)的提高發(fā)送數(shù)據(jù)包的數(shù)量來試探網(wǎng)絡(luò)的情況,它的主要原理就是:當(dāng)發(fā)送方每收到一個(gè) ACK,擁塞窗口 cwnd 的大小就會(huì)加 1。當(dāng)然也不可能無限制的增加擁塞窗口 cwnd 的大小,有一個(gè)叫慢啟動(dòng)門限 ssthresh (slow start threshold)狀態(tài)變量,當(dāng)cwnd 小于該值時(shí)就增加,大于等于該值時(shí)就會(huì)啟動(dòng)擁塞避免算法。慢開始算法只是在TCP連接建立時(shí)和網(wǎng)絡(luò)出現(xiàn)超時(shí)時(shí)才使用
-
擁塞避免算法:進(jìn)入擁塞避免算法后,它的規(guī)則是:每當(dāng)收到一個(gè) ACK 時(shí),擁塞窗口cwnd 增加 1/cwnd,假設(shè)cwnd現(xiàn)在是8,那么進(jìn)入擁塞避免算法后,收到ACK時(shí),它增加了1/8。也就是說增長(zhǎng)變的緩慢了,即使緩慢的增長(zhǎng),它也是無限制的,這樣網(wǎng)絡(luò)就會(huì)慢慢進(jìn)入了擁塞的狀況,當(dāng)出現(xiàn)包丟失,觸發(fā)重傳機(jī)制的時(shí)候,就進(jìn)入了擁塞發(fā)生算法。
-
擁塞發(fā)生算法:當(dāng)網(wǎng)絡(luò)出現(xiàn)擁塞,也就是會(huì)發(fā)生數(shù)據(jù)包重傳,觸發(fā)重傳機(jī)制,前面我們知道重傳機(jī)制分為超時(shí)重傳和快速重傳兩種情況,當(dāng)發(fā)生了超時(shí)重傳時(shí)才會(huì)使用擁塞發(fā)生算法,此時(shí)它會(huì)將ssthresh 設(shè)置為cwnd/2 ,并將cwnd 重置為初始值。接著,就重新開始慢啟動(dòng),慢啟動(dòng)是會(huì)突然減少數(shù)據(jù)流的。這種方式太激進(jìn)會(huì)造成網(wǎng)絡(luò)卡頓。當(dāng)發(fā)生快速重傳時(shí),TCP 認(rèn)為這種情況不嚴(yán)重,因?yàn)榇蟛糠譀]丟,只丟了一小部分,則 ssthresh 和 cwnd 變化如下,cwnd = cwnd/2 ,也就是設(shè)置為原來的一半;ssthresh = cwnd。進(jìn)入快速恢復(fù)算法
-
快速恢復(fù)算法: 快速重傳和快速恢復(fù)算法一般同時(shí)使用,進(jìn)入快速恢復(fù)算法后,擁塞窗口 cwnd = ssthresh + 3,重傳丟失的數(shù)據(jù)包??焖倩謴?fù)是針對(duì)擁塞發(fā)生后對(duì)慢啟動(dòng)的優(yōu)化。
tcp 粘包問題
TCP粘包就是指發(fā)送方發(fā)送的若干包數(shù)據(jù)到達(dá)接收方時(shí)粘成了一包,導(dǎo)致數(shù)據(jù)包不能完整的體現(xiàn)發(fā)送的數(shù)據(jù)。導(dǎo)致TCP粘包的問題可能是發(fā)送方,也可能是接收方。
發(fā)送方
小數(shù)據(jù)包加劇了網(wǎng)絡(luò)帶寬的浪費(fèi),為了解決這個(gè)問題,引入了Nagle算法,該算法的思路是延時(shí)發(fā)送數(shù)據(jù),它會(huì)將多個(gè)小的數(shù)據(jù)包合并成一個(gè)大的包一次性發(fā)送出去,以達(dá)到提升網(wǎng)絡(luò)傳輸效率的目的。但是接收方并不知曉發(fā)送方合并的數(shù)據(jù)包,而且數(shù)據(jù)包的合并在TCP協(xié)議中是沒有分界線的,所以這就會(huì)導(dǎo)致接收方不能還原其本來的數(shù)據(jù)包,這就會(huì)造成粘包問題。
接收方
接收數(shù)據(jù)方的應(yīng)用層沒有及時(shí)讀取接收緩沖區(qū)中的數(shù)據(jù),導(dǎo)致后面的數(shù)據(jù)包發(fā)送過來到達(dá)了緩存區(qū),這樣接收方的應(yīng)用層讀取緩存區(qū)數(shù)據(jù)時(shí)粘連了其他組的數(shù)據(jù)包。
還有如:要發(fā)送的數(shù)據(jù)大于TCP發(fā)送緩沖區(qū)剩余空間大小,將會(huì)發(fā)生拆包問題。文章來源:http://www.zghlxwxcb.cn/news/detail-499149.html
如何解決?
- 發(fā)送端給每個(gè)數(shù)據(jù)包添加包首部,首部中應(yīng)該至少包含數(shù)據(jù)包的長(zhǎng)度,這樣接收端在接收到數(shù)據(jù)后,通過讀取包首部的長(zhǎng)度字段,便知道每一個(gè)數(shù)據(jù)包的實(shí)際長(zhǎng)度了。
- 發(fā)送固定長(zhǎng)度的消息(不夠的可以通過補(bǔ)0填充)這樣接收端每次從接收緩沖區(qū)中讀取固定長(zhǎng)度的數(shù)據(jù)就可以了,但是這種方式靈活性不高,實(shí)際中很少用
- 添加特殊字符作為邊界,可以在兩個(gè)用戶消息之間插入一個(gè)特殊的字符串,這樣接收方在接收數(shù)據(jù)時(shí),讀到了這個(gè)特殊字符,就把認(rèn)為已經(jīng)讀完一個(gè)完整的消息。例如:HTTP 通過設(shè)置回車符、換行符作為 HTTP 報(bào)文協(xié)議的邊界。需要注意的是,如果剛好消息內(nèi)容里有這個(gè)特殊字符則需要進(jìn)行轉(zhuǎn)義或者在特殊字符之后加上校驗(yàn)數(shù)據(jù)等。
rpc是什么?
RPC即遠(yuǎn)程過程調(diào)用,通常包含傳輸協(xié)議 和 序列化協(xié)議,傳輸協(xié)議:可以基于http協(xié)議實(shí)現(xiàn)、也可以基于tcp協(xié)議實(shí)現(xiàn)。序列化協(xié)議:有基于文本編碼的 json 協(xié)議;也有二進(jìn)制編碼的 protobuf、hession 等協(xié)議文章來源地址http://www.zghlxwxcb.cn/news/detail-499149.html
到了這里,關(guān)于TCP如何保證可靠性,TCP如何實(shí)現(xiàn)可靠性傳輸?shù)牡奈恼戮徒榻B完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!