一种基于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甚至更大。这就会致使客户端之间有长时间的不一样步,这是该业务场景没法接受的。

解决思路:客户端一次说明全部丢包,服务端接受后一次性返回。

相关文章
相关标签/搜索