天天看點

UDP的可靠性傳輸

UDP和TCP的差別

Tcp和udp都是屬于TCP/IP協定(傳輸層協定)。

TCP

TCP(Transmission Control Protocol,傳輸控制協定)是面向連接配接的協定,也就是說,在收發資料前,必須和對方建立可靠的連接配接。 一個TCP連接配接必須要經過三次握手,斷開連接配接時需要四次揮手。

TCP的可靠性主要展現在什麼方面呢?

1. 應用資料被分割成TCP認為最合适發送的資料塊。

這個和UDP完全不同,應用程式将産生的資料報長度将保持不變。由TCP傳遞給IP的資訊機關稱為封包段或段。最大封包段(MSS)表示TCP傳往另一端的最大塊資料的長度。連接配接建立時,雙方都需要通告自己的MSS。預設情況下MSS的值為536位元組(可以加上20位元組的IP首部和20位元組的TCP首部)。對于一個以太網,最大的MSS可達到1460位元組(1500(MTU) - 20(IP) - 20(TCP))。

2. 當TCP發出一個段之後,它啟動一個定時器,等待目的端确認收到這個封包段,如果不能及時收到一個确認,将重發這個封包段。

3. 當TCP收到另一端的資料,他将發送一個确認。這個确認不是立即發送,而是延遲幾分之一秒。

4. TCP将保持它首部和資料的校驗和。這個是一個端到端的檢測,目的是檢測資料在傳輸時的任何變化,如果有收到段的檢驗和有差錯,tcp将丢棄這個封包段和不确認收到此封包段。

5. 既然tcp封包段作為ip資料報來傳輸,而ip資料報的到達可能會失序,是以tcp封包段的到達可能會失序。如果必要,tcp将對收到的資料進行重新排序。

6. ip資料包會發生重複,tcp的接收端必須丢棄重複的資料。

7. TCP提供流量控制。

UDP的可靠性傳輸

UDP

UDP(UserDatagramProtocol)是一個簡單的面向消息的傳輸層協定,盡管UDP提供标頭和有效負載的完整性驗證(通過校驗和),但它不保證向上層協定提供消息傳遞,并且UDP層在發送後不會保留UDP 消息的狀态。是以,UDP有時被稱為不可靠的資料報協定。如果需要傳輸可靠性,則必須在使用者應用程式中實作。

UDP的可靠性傳輸
關注+私信扣1,免費分享2022最新最全學習提升資料包,資料内容包括《Andoird音視訊開發必備手冊+音視訊最新學習視訊+大廠面試真題+2022最新學習路線圖》(C/C++,Linux,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)等等 
UDP的可靠性傳輸

 為什麼要使用UDP傳輸可靠性資料

UDP(User Datagram Protocol)傳輸與IP傳輸非常類似,它的傳輸方式也是"Best Effort"的,是以UDP協定也是不可靠的。我們知道TCP就是為了解決IP層不可靠的傳輸層協定,既然UDP是不可靠的,為什麼不直接使用IP協定而要額外增加一個UDP協定呢?

一個重要的原因是IP協定中并沒有端口(port)的概念。IP協定進行的是IP位址到IP位址的傳輸,這意味者兩台計算機之間的對話。但每台計算機中需要有多個通信通道,并将多個通信通道配置設定給不同的程序使用。一個端口就代表了這樣的一個通信通道。UDP協定實作了端口,進而讓資料包可以在送到IP位址的基礎上,進一步可以送到某個端口。

對于一些簡單的通信,我們隻需要“Best Effort”式的IP傳輸就可以了,而不需要TCP協定複雜的建立連接配接的方式(特别是在早期網絡環境中,如果過多的建立TCP連接配接,會造成很大的網絡負擔,而UDP協定可以相對快速的處理這些簡單通信)

在使用TCP協定傳輸資料時,如果一個資料段丢失或者接收端對某個資料段沒有确認,發送端會重新發送該資料段。TCP重新發送資料會帶來傳輸延遲和重複資料,降低了使用者的體驗。對于遲延敏感的應用,少量的資料丢失一般可以被忽略,這時使用UDP傳輸将能夠提升使用者的體驗。

UDP将資料從源端發送到目的端時,無需事先建立連接配接,沒有使用TCP中的确認技術或滑動視窗機制,是以UDP不能保證資料傳輸的可靠性,也無法避免接收到重複資料的情況。

UDP傳輸的可靠性由應用層負責,由應用程式根據需要提供封包ACK機制、重傳機制、序号機制、重排機制和視窗機制。這些TCP已經都具備了。

如何使用UDP傳輸可靠性資料

這裡我們主要介紹一種開源UDP的可靠性方案KCP:

https://github.com/skywind3000/kcp

KCP主要的優勢展現在以下方面:

以10%-20%帶寬浪費的代價換取了比 TCP快30%-40%的傳輸速度。

RTO翻倍vs不翻倍:TCP逾時計算是RTOx2,這樣連續丢三次包就變成RTOx8了,十分恐怖,而KCP啟動快速模式後不x2,隻是x1.5(實驗證明1.5這個值相對比較好),提高了傳輸速度。

選擇性重傳 vs 全部重傳: TCP丢包時會全部重傳從丢的那個包開始以後的資料, KCP是選擇性重傳,隻重傳真正丢失的資料包。

快速重傳(跳過多少個包馬上重傳)(如果使用了快速重傳,可以不考慮RTO))

發送端發送了1,2,3,4,5幾個包,然後收到遠端的ACK: 1, 3, 4, 5,當收到ACK3時, KCP知道2被跳過1次,收到ACK4時,知道2被跳過了2次,此時可以認為2号丢失,不用等逾時,直接重傳2号包,大大改善了丢包時的傳輸速度。

UNA vs ACK+UNA:ARQ模型響應有兩種, UNA(此編号前所有包已收到,如TCP)和ACK(該編号包已收到),光用UNA将導緻全部重傳,光用ACK則丢失成本太高,以往協定都是二選其一,而 KCP協定中, 除去單獨的 ACK包外,所有包都有UNA資訊。

非退讓流控:KCP正常模式同TCP一樣使用公平退讓法則,即發送視窗大小由:發送緩存大小、接收端剩餘接收緩存大小、丢包退讓及慢啟動這四要素決定。但傳送及時性要求很高的小資料時,可選擇通過配置跳過後兩步,僅用前兩項來控制發送頻率。以犧牲部分公平性及帶寬使用率之代價,換取了開着BT都能流暢傳輸的效果。

名詞說明:

使用者資料:應用層發送的資料,如一張圖檔2Kb的資料

MTU:最大傳輸單元。即每次發送的最大資料

RTO: Retransmission TimeOut,重傳逾時時間。

cwnd:congestion window,擁塞視窗,表示發送方可發送多少個KCP資料包。

與接收方視窗有關,與網絡狀況(擁塞控制)有關,與發送視窗大小有關。

rwnd:receiver window,接收方視窗大小,表示接收方還可接收多少個KCP資料包

snd_queue:待發送KCP資料包隊列

snd_nxt:下一個即将發送的kcp資料包序列号

snd_una:下一個待确認的序列号

KCP的使用方式

建立 KCP對象: ikcpcb *kcp = ikcp_create(conv, user);

設定傳輸回調函數(如UDP的send函數): kcp->output = udp_output;

真正發送資料需要調用sendto

循環調用 update: ikcp_update(kcp, millisec);

輸入一個應用層資料包(如UDP收到的資料包) :ikcp_input(kcp,received_udp_packet,received_udp_size);

我們要使用recvfrom接收,然後扔到kcp裡面做解析

發送資料: ikcp_send(kcp1, buffer, 8); 使用者層接口

接收資料: hr = ikcp_recv(kcp2, buffer, 10);

UDP的可靠性傳輸

kcp配置模式

工作模式: int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc)

nodelay :是否啟用 nodelay模式, 0不啟用; 1啟用。

interval :協定内部工作的 interval,機關毫秒,比如 10ms或者 20ms

resend :快速重傳模式,預設0關閉,可以設定2(2次ACK跨越将會直接重傳)

nc :是否關閉流控,預設是0代表不關閉, 1代表關閉。

普通模式: ikcp_nodelay(kcp, 0, 40, 0, 0);

極速模式: ikcp_nodelay(kcp, 1, 10, 2, 1)

最大視窗: int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd);

該調用将會設定協定的最大發送視窗和最大接收視窗大小,預設為32,機關為包。

最大傳輸單元: int ikcp_setmtu(ikcpcb *kcp, int mtu);

kcp協定并不負責探測 MTU,預設 mtu是1400位元組

最小RTO:不管是 TCP還是 KCP計算 RTO時都有最小 RTO的限制,即便計算出來RTO為

40ms,由于預設的 RTO是100ms,協定隻有在100ms後才能檢測到丢包,快速模式下為

30ms,可以手動更改該值: kcp->rx_minrto = 10;

kcp的協定頭

UDP的可靠性傳輸

conv:連接配接号。 UDP是無連接配接的, conv用于表示來自于哪個

用戶端。對連接配接的一種替代

cmd:指令字。如, IKCP_CMD_ACK确認指令,

IKCP_CMD_WASK接收視窗大小詢問指令,

IKCP_CMD_WINS接收視窗大小告知指令,

frg:分片,使用者資料可能會被分成多個KCP包,發送出去

wnd:接收視窗大小,發送方的發送視窗不能超過接收方

給出的數值

ts:時間序列

sn:序列号

una:下一個可接收的序列号。其實就是确認号,收到

sn=10的包, una為11

len:資料長度

data:使用者資料

test kcp代碼:

https://github.com/birate-wz/wz_utils/tree/main/kcp 

繼續閱讀