您好,登錄后才能下訂單哦!
網絡通信中的ACK、NACK與REX是什么?相信大部分人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,話不多說,一起往下看吧。
ACK:Acknowledgement,它是一種正向反饋,接收方收到數據后回復消息告知發送方。
NACK:Negative Acknowledgement,則是一種負向反饋,接收方只有在沒有收到數據的時候才通知發送方。
REX:Retransmission,重傳,當發送方得知數據丟失后,重新發送一份數據。
問題 1:接收方如何判斷數據包是否丟失 ?
解決方案:編號,每一個 packet 都打上一個序列號(Seq number),接收端發現序列號跳變/缺失,則可以判斷數據包丟失了。
這就是為什么 TCP 協議的包頭(packet header)里面要定義一個序列號字段的原因(如圖紅色標記):
擴展一下,我們再看看 UDP 協議的包頭(packet header)的定義:
可以看到,UDP header 沒有用任何字段來標識序列號(Seq number),由此可見,UDP 是一個完全不關心是否丟包的傳輸協議。
問題 2:發送方如何確認數據包已經丟失 ?
有幾種常見的方案,這里先簡單介紹下,不詳細展開細節。
1. 停等協議
發送方每次只發送一個包,同時啟動一個定時器。如果定時器超時依然沒有收到這個包的 ACK,則認為丟包,重傳這個包。如果收到 ACK,則重置定時器并發送下一個包。
問題:丟包的判斷和傳輸效率非常低。
2. 連續 ARQ 協議 & 滑窗協議
發送方維持著一個一定大小的發送窗口,位于發送窗口內的所有包可以連續發送出去,中途不需要依次等待對方的 ACK 確認。
接收方通常采用 積累確認模式,即不必對每一個包逐個發送 ACK,而是在連續收到幾個包后,對順序到達的最后一個包序號發送 ACK,表示:這個包及之前的所有包都已正確收到了。
積累確認模式 的缺點:亂序比較嚴重的網絡下,效率非常低,部分已經送到但沒有按照順序送達的包也必須重傳。
改進方案:選擇性重傳(注:KCP/SRT 協議有實現):對于順序的包,發送積累確認;跳躍的包,發送 ACK;發送端只重傳真正丟失的數據包。
3. 快速重傳
使用 ACK 機制的傳輸協議,通常在發送端等到某個數據包的 ACK 超時后,才會重傳數據包,不夠及時。
快速重傳:如果接收端接收到了序號跳躍的數據包,則立即給發送方發送最后一個連續的數據包的 ACK(重復確認) 。如果發送端收到連續 3 個重復確認,則認為該 ACK 的下一個數據包丟失了,并立即重傳該丟失的數據包。
4. NACK
接收方定時把所有未收到的包序號通過反饋報文通知到發送方進行重傳。
帶來的改進:減少的反饋包的頻率和帶寬占用,同時也能比較及時地通知發送方進行丟包重傳。
問題 3:重傳超時的計算規則 ?
RTO:重傳超時時間(Retransmission Timeout),它是發送端用來判斷數據包丟失和執行重傳的最重要的一個參數。
很明顯,它應該是一個隨網絡傳輸的 RTT(往返時間)而變化的值,理想情況下,RTO 的值不小于 RTT 即可(從數據包發送到對方的 ACK 到達的最短時間),實際情況下,RTT 變化是非常頻繁的,每一次傳輸的 RTT 可能都不一樣,如果粗暴地設置 RTO = RTT 則一定會導致重傳過度頻繁。
因此 TCP 協議采用的 RTO 計算方法是:
1. 基于多次 RTT 測量,給出一個平滑后的 RTT 預估值:SRTT(Smoothed Round Trip Time)
2. RTO = SRTT + 某種系數(防止抖動的閾值)
3. 進一步,系統級別設置 RTO 的下限為 100ms 或 200ms,防止異常值
4. 更進一步,對于重傳包的 RTO,加上一個退避算法,比如,每重傳一次,則 RTO = 2 RTO 這樣的方式來減少對一個包進行頻繁的重傳
注:關于重傳包 RTO 的退避策略,KCP 經過實驗證明 ,RTO 的退避系數使用 1.5 倍的效果比 2 倍的效果更好。
問題 4:發送方的數據包要緩存多久 ?
發送端為了能實現重傳,必須在本地將發送的數據包緩存起來,在需要重傳的時候,即可從緩存隊列里面取到該數據包進行重傳。
對于 ACK 模型的傳輸協議(如:TCP),在收到對方的 ACK 之后刪除緩存即可,那如果是 NACK 模型的傳輸協議,如何更新和清理這個緩存隊列呢 ?
1. 方案一:基于 RTT 和 NACK 時間間隔
假設當前的 RTT(網絡往返時間)是 rtt ms,NACK 的反饋時間間隔是 x ms,那么,一個數據包在發送緩存隊列中最少的存活時間應該是:
cache time = 2 * rtt + x
假設在這個時間后內收到的 NACK 反饋包沒有指出該數據包丟失,則可以刪除了。當然,類似 RTO 所涉及到的問題原因,rtt 是頻繁變化的,因此單純依靠這個理論值來刪除緩存并不安全,建議增加一定的冗余。
2. 方案二:基于業務場景
對于實時音視頻通信場景,對延時有一定的要求,因此,超過 1s 的數據,就沒有必要再重傳了。或者,假設視頻的 GOP 是 2s,那么,最多在緩存隊列保持 2s 的數據包即可。
問題 5:接收端多久發送一次 nack 請求 ?
假設接收端發現數據包發生序列號跳躍后立即發送 NACK 請求,由于 UDP 數據包可能會亂序到達,因此這種方案會導致過多的無效重傳請求。
更加合理的方案是:每間隔指定的時間(比如:WebRTC 使用的是 10ms)發送一次 NACK 請求,一次性帶上這段時間所有的丟包序號。
問題 6:哪些丟失的數據包會放入 nack 請求隊列中 ?
接收端的重傳請求的隊列也應該有一定的機制,不是所有的丟包都必須要求重傳,比如:
1. 當前音頻播放到了 timestamp 為 x 的時間點了,其實在 timestamp < x 的所有丟失的音頻包都不應該再請求重傳了,視頻也是如此。
2. 作為 SFU 中轉服務器,它沒有播放時間的概念,因此方法 1 并不適用,但是可以參考發送端緩存的邏輯,假設 GOP 是 2s,則對比最新的 packet 時間戳,丟失的數據包時間在 2s 之前的數據,則沒有必要再申請重傳了。
補充一點,作為 SFU 中轉服務器,可能會遇到下述情況,即:收到客戶端的 NACK 請求的數據包不再自己的 cached packet list 里面:
SFU 作為客戶端上行的接收端,發現丟包也跟普通的接收端一樣,定時主動地向源頭發送 NACK 請求;反過來,SFU 作為客戶端下行的發送端,收到 NACK 請求后,如果發現不在 cached list,則標記一下,一旦收到源頭的重傳,則第一時間轉發到下行。
問題 7:如何防止某個數據包頻繁的 nack 請求 ?
參考 WebRTC 的實現,有如下防止策略:
1. 當一個丟失的包被 NACK 請求重傳了至少 N 次(如:10次)后依然沒有成功收到,則應該放棄了(很可能發送端也已經沒有這個數據包的緩存了)
2. 考慮到重傳請求在發送端的響應時間及網絡 RTT,接收端應該確保在一定時間周期內不要頻繁地發送對同一個數據包的 NACK 重傳請求。(如:WebRTC 選擇的時間周期是 5 + RTT * 1.5),即:在這個時間周期內不再重復發送同一個數據包的 NACK 請求。
3. 當 nack reqeust list 里面的數據包太多了(比如:超過 1000),則應該考慮清理一下(網絡太弱了),對于視頻的話,直接發送 IDR request,重新申請新的 GOP 數據。
問題 8:重傳包的優先級?FEC 包是否需要重傳 ?
考慮到丟包 -> 重傳已經耽誤了數據包的達到時間了,因此,重傳包的優先級應該大于普通的數據包,當然,也應該有根據重傳次數優先級逐步遞減的策略。
FEC 包不需要,意義不大,FEC 的目的是為了減少重傳而增加的冗余包,丟掉沒有致命的影響,我們只需要重傳價值更大的數據包即可。
問題 9:RTCP 協議的 NACK 報文是如何定義的 ?
NACK 報文的定義在 [rfc4585] 文檔中定義。
RTCP 的反饋報文包頭定義如下,FMT 和 PT 決定了該報文的類型,FCI 則是該類型報文的具體負載:
協議規定的 NACK 反饋報文的 PT= 205,FMT=1,FCI 的格式如下(可以附帶多個 FCI,通過 header 的 length 字段來標示其長度):
這里的設計比較巧妙,它可以一次性攜帶多個連續的數據包的丟包情況:
PID(Packet identifier),即為丟失的 RTP 數據包的序列號
BLP(Bitmao of Lost Packets),通過掩碼的方式指出了接下來 16 個數據包的丟失情況
看完上述內容,你們對網絡通信中的ACK、NACK與REX大概了解了嗎?如果想了解更多相關文章內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。