一種基於WebRTC與UDP組播的一對多遠程控制桌面的實現思路

  • 蘇格團隊
  • 做者:Jason

前言

筆者最近收到要求 遠程控制局域網內多N臺終端同步操做 的需求(功能相似windows上的遠程桌面)。 最終筆者實現了一種不太成熟,不太穩定,但基本知足現階段需求的方案,且將來會持續迭代。前端

出於種種複雜緣由,筆者沒法使用如今一些市面上很成熟的解決方案。但因爲該項目僅限於內部人員使用,即對方案的成熟性,可靠性,可維護性沒有太多要求(面部表情逐漸舒展)。windows

分析

遠程控制桌面,不管是1對1仍是1對多。核心的數據的無非就是倆類。音視頻信息,控制信息 (鍵盤,鼠標,快捷鍵等)。當獲得這倆個數據時,咱們就能夠 在控制端實時獲取受控端的視頻信息以及傳輸控制指令 。那麼接下的操做就是:bash

1.獲取被控制端的視頻流

做爲一個前端開發工程師,對於如何獲取設備的音視頻信息這件事,本能的我就想起了 WebRTC (網頁即時通信)協議。
而後就是分析具體的設備和場景是否適用,一頓腦補分析後,我看行(主要是WebRTC自己強大)。服務器

2.發送與接收控制信息

因爲具體業務和某些神祕的限定和權衡。採用TCP協議傳輸消息是不可能的。那沒啥好說的了,UDP救我!
雖然他們一次次給我帶來的都是,這個不行,那個也不行 的種種限制,可是好消息也是有的,在一系列複雜的操做後,我拿到了受控方模擬鼠標和鍵盤操做的接口。得,齊活!網絡

UDP傳輸不可靠怎麼辦?

開發初期,筆者遇到的最大的問題就是UDP的傳輸是無鏈接的,不保證可靠性,可是在該業務場景下 多個受控端須要對比一段操做後的不一樣來上報異常,若是由於網絡的問題致使接收到的指令又略微不一樣,那 可用性就會大的下降性能

衆所周知,UDP的傳輸是不可靠的,它不像TCP那樣保證數據有序,不丟失的傳輸。可是限制就是在那裏,讓你頭大-.-。 那麼問題來了如何 在該場景下確保UDP可靠傳輸優化

如何解決該場景下UDP傳輸不可靠問題

在通過一系列的腦補事後,個人就在 腦海裏產生了如下對話spa

(1) 毫無頭緒階段

A:一個服務端控制多個客戶端,他們之間怎麼傳數據?
B:UDP組播?
A:業務容許丟包嗎?
B:不容許,並且還要有序執行。
複製代碼

總結:該場景下筆者只能使用UDP組播/廣播,但又不容許發生丟包。

(2) 提出設想階段

A:發送端每發一條消息,接收端回服一條確認收到?
B:服務端一條消息發出去,而後接受幾十條確認消息?若是一秒發送30條數據呢?
A: 一臺客戶端經過組播發送丟包請求後,其餘客戶端接收到後就不發送相同丟包?
B:多臺客戶端同時丟包怎麼辦?隨機等待時間發送嗎?這樣作的話,延遲呢?不一樣步怎麼辦?並且等待的時間是否是還得監聽信道?
複製代碼

總結:模仿TCP的確認機制基本不可行的,須要走其餘的路。

(3) 初步決定方案A

A:若是客戶端不能回覆給服務端肯定收到的消息,那就只能客戶端本身肯定丟包?
B:對,客戶端須要判斷本身丟包,而後反饋給服務端!
A:客戶端惟一的信息來源就是服務端以往發的包,因此就是客戶端發的包之間自帶聯繫。
B:客戶端發包的時候加上包的Index?而後客戶端根據上下倆個包Index是不是連續的來判斷是否丟包?
複製代碼

總結:客戶端發包的時加上遞增的Index,服務端經過Index判斷是否丟包。

(4) 緩衝區的創建和維護

B: 好比如今服務器下發了包1,2,3後又下發4.
   客戶端1收到了所有的消息,它保持沉默。
   客戶端2丟失了信息3,當收到信息4時,它發現前一個包是信息2.因而它就會去給服務器發丟失信息3的反饋包?
A: 怎麼發?點對點仍是走組播?
B:走組播,若是其它接收端也丟了這個包,就能夠收到了。沒丟也能夠判斷Index來得知這是一個已執行過的包。
   同時服務端須要維護一個緩衝區。須要清除已確認發送成功的數據,否則內存會爆。

A:可服務端沒辦法肯定接收端端包是否收到的啊?

B:若是丟包的機制生效。當客戶端反饋包9丟失,就意味着包9以前的包該客戶端都收到了。那就能夠把以前的包清除了。
   固然也須要設置一個最大值。
A:但是存在多個發送端啊!其中一個收到後,服務端清除該包。一會後另外一臺客戶端又反饋丟了該包,怎麼辦?
B:和已經反饋過收到的客戶端要唄!
複製代碼

總結:服務端維護一個具備最大長度的緩衝區,並在確認收到後清除無效數據。

(5) 等待和強制執行機制

A:回到剛纔,客戶端收到信息2後緊接着收到信息4,判斷信息3丟了。發送信息3的再次傳送請求時,已接收到的信息4怎麼辦?
   若是在等待信息3的過程當中,信息5,信息6,信息7都接受到了有如何處理?一直等着嗎?仍是一個倆個包就忽略丟失?
B:絕對不能忽略!由於客戶端不知道丟的包是什麼操做,若是是點擊,忽視會致使客戶端之間信息不一樣步很嚴重!因此只能等。
   同事在收到包後,檢測是否有更大Index的包存在。若是有,強制執行該包。
複製代碼

總結:客戶端一樣維護一個緩衝區,丟包時等待同時接受新的數據。收到包後強制執行全部已收到的包。

(6) 多個通道

B:這樣的話,全部的客戶端收到的消息都是同樣的,你們的包Index都是同一個。可是若是此時須要點對點通訊怎麼辦?
A:每一個客戶端都維護一套緩衝區?
B:不可能,成本太大。私聊走私聊通道,能夠不確保可靠性。
複製代碼

總結:服務端須要有組播和點對點通訊倆套機制,點對點能夠不確保可靠性。

(7) 包加權

A:丟包以後等着回傳有可能致使延遲太大,多個客戶端不一樣步。
B:逆推,不須要等 --> 忽視丟包 --> 丟失包不重要 --> 你判斷出包不重要。
   服務端發包時帶上過往的N個包的權重。這樣客戶端接受到包時就知道前面的包的權重了!
A:由於你是經過下一個包來判斷上一個包是否丟包的,因此若是下一個包攜帶以前N個包的重要程度。理論上就可能忽視丟包了!
B:因此,須要在發送端給包的權限分等級。好比,鼠標移動等級爲1,鼠標點擊爲10。
複製代碼

總結:爲了能夠作到忽視丟包,須要肯定每個包的權重,作法就是在每個包里加上以前N個包的權重。

(8) 合包和拆包

A:有一個需求將已段時間的操做存儲。而後隨時能夠一次性所有發送給接收端。
B:一次性發送大的數據會致使包在IP層被分片,包越大被分的片越多。該業務腳本會有多大?
A:和錄製時長成正比,並且用戶操做不可揣測,且不應被限定。因此咱們須要在服務端進行手動拆包在客戶端進行合包。
B:因此須要給拆分的包加上總包長,該包在總包中的Index等。
A:拆分過的包發送時依然遵循上述可靠協議發送,確保能夠收到全部的分包。
複製代碼

總結:爲了不在IP層被分片,須要服務端去手動分包,而後在客戶端進行合包。

實現過程當中遇到的那些問題

問題1 客戶端鼠標卡頓

出於對發送信息不能太頻繁的考量,鼠標移動的過程當中 發送數據作了節流 。代價就是接收端的鼠標收到了一羣不連續的的位置點。因爲服務端是經過WebRTC顯示某一臺客戶端的畫面來進行操做的,因此用戶使用體驗不好。調試

解決思路:

若是服務端作了鼠標移動事件節流,那麼客戶端只須要作鼠標移動插值就好了。即在接受到的倆個鼠標移動事件中,本身計算中間值進行插值。實測優化效果很是明顯。code

問題2 客戶端短期內反覆發送丟包致使服務端負載大

在調試過程當中,發現客戶端在丟失數據包到接受到該丟失包的過程當中,會屢次的發送丟包信息給服務端。然後服務端又會在一段時間後返回多條數據(由於收到了多條丟包請求重傳的包).

解決思路:爲了形成沒必要要的性能損失,咱們對發送同一個包的丟包請求作了節流。

問題3 連續丟包致使客戶端卡頓

通過一些實踐發現一旦發生丟包很容易是連續丟失。好比客戶端收到的信息Index序列是1,2,3,4,10. 此事客戶端認定包5丟失,等到包5被接受到,再去發送包6的丟失信息。如此往復,等到包9接受到時,其餘客戶端能夠已經接受到了包20,30甚至更大。這就會致使客戶端之間有長時間的不一樣步,這是該業務場景沒法接受的。

解決思路:客戶端一次說明全部丟包,服務端接受後一次性返回。

相關文章
相關標籤/搜索