WebRTC学习笔记四 RTCDataChannel
创始人
2024-03-03 10:35:16
0

一、RTCDataChannel

    简单来说,RTCDataChannel 就是在点对点连接中建立一个双向的数据通道,从而获得文本、文件等数据的点对点传输能力。它依赖于流控制传输协议(SCTP),SCTP 是一种传输协议,类似于 TCP 和 UDP,可以直接在 IP 协议之上运行。但是,在 WebRTC 的情况下,SCTP 通过安全的 DTLS 隧道进行隧道传输,该隧道本身在 UDP 之上运行

    这个示例在Connect之后,可以输入文本后,使用send发送到另一端。注意: 尽管参与连接的两端都在同一页面,我们将启动连接的一端称为 "local" 端,另一端称为 "remote" 端。

1.建立本地节点

localConnection = new RTCPeerConnection();
​
sendChannel = localConnection.createDataChannel("sendChannel");
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;

    第一步是建立该连接的 "local" 端,它是发起连接请求的一方。 下一步是通过调用RTCPeerConnection.createDataChannel() 来创建 RTCDataChannel 并设置事件侦听以监视该数据通道, 从而获知该通道的打开或关闭 (即获得该对等连接的通道打开或者关闭的时机)。

    请务必记住该通道的每一端都拥有自己的 RTCDataChannel 对象。

    createDataChannel方法允许传入第二个参数进行不同的配置

  • reliable 设置消息传递是否进行担保

  • ordered 用来设置消息的接受是否需要按照发送时的顺序

  • maxRetransmitTime 设置消息发送失败时,多久重新发送

  • maxRetransmits 设置消息发送失败时,最多重发次数

  • protocol 设置强制使用其他子协议,但当用户代理不支持该协议时会报错

  • negotiated 此选项用来设置开发人员是否有责任在两边创建数据通道,还是浏览器来自动完成这个步骤

  • id 这个用来设置通道的唯一标识,可以在多通道时进行区分

    这些配置项很多,不过大部分只在高级应用中才会使用。主要使用的配置项是reliable和 ordered,当设置为true时数据通道表现得更像TCP,设置为False时表现得更像UDP。

    negotiated 为解决两边用户同步创建数据通道而设置。用来处理ondatachannel事件触发时的不同行为。默认值是false,表示浏览器会在通道另一边自动触发这个事件,告诉它这个新通道。如果设置成True,开发者需要自己在通道两边创建相同ID的数据通道。

【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~

  

2.建立远程节点

remoteConnection = new RTCPeerConnection();
remoteConnection.ondatachannel = receiveChannelCallback;

    远程端的建立过程类似“local”端, 但它无需自己创建 RTCDataChannel , 因为我们将通过上面建立的渠道进行连接。 我们创建对 datachannel 的事件处理回调;数据通道打开时该逻辑将被执行, 该回调处理将接收到一个 RTCDataChannel 对象,此过程将在文章后面部分描述。

3.设立ICE 候选人

    下一步为每个连接建立 ICE 候选侦听处理, 当连接的一方出现新的 ICE 候选时该侦听逻辑将被调用以告知连接的另一方此消息。

    注意: 在现实场景,当参与连接的两节点运行于不同的上下文,建立连接的过程或稍微复杂些,每一次双方通过调用RTCPeerConnection.addIceCandidate(),提出连接方式的建议 (例如: UDP,、中继UDP 、 TCP之类的) , 双方来回往复直到达成一致。本文既然不涉及现实网络环境,因此我们假定双方接受首次连接建议。

    localConnection.onicecandidate = e => !e.candidate|| remoteConnection.addIceCandidate(e.candidate).catch(handleAddCandidateError);
​remoteConnection.onicecandidate = e => !e.candidate|| localConnection.addIceCandidate(e.candidate).catch(handleAddCandidateError);

    我们配置每个 RTCPeerConnection 对于事件 icecandidate 建立事件处理。

4.启动连接尝试

    建立节点连接的最后一项是创建一个连接offer.

    localConnection.createOffer().then(offer => localConnection.setLocalDescription(offer)).then(() => remoteConnection.setRemoteDescription(localConnection.localDescription)).then(() => remoteConnection.createAnswer()).then(answer => remoteConnection.setLocalDescription(answer)).then(() => localConnection.setRemoteDescription(remoteConnection.localDescription)).catch(handleCreateDescriptionError);

5.数据通道(data channel)的连接

    RTCPeerConnection 一旦open, 事件datachannel 被发送到远端以完成打开数据通道的处理, 该事件触发 receiveChannelCallback() 方法,如下所示:

  function receiveChannelCallback(event) {receiveChannel = event.channel;receiveChannel.onmessage = handleReceiveMessage;receiveChannel.onopen = handleReceiveChannelStatusChange;receiveChannel.onclose = handleReceiveChannelStatusChange;}

    事件datachannel 在它的channel属性中包括了: 对代表remote节点的 channel的RTCDataChannel 的指向, 它保存了我们用以在该channel上对我们希望处理的事件建立的事件监听。 一旦侦听建立, 每当remote节点接收到数据 handleReceiveMessage() 方法将被调用, 每当通道的连接状态发生改变 handleReceiveChannelStatusChange() 方法将被调用, 因此通道完全打开或者关闭时我们都可以作出相应的相应。

6.对通道状态变化的处理

    local节点和remote节点采用同样的方法处理表示通道连接状态变更的事件。

    当local节点遭遇open 或者 close 事件, handleSendChannelStatusChange() 方法被调用:

function handleSendChannelStatusChange(event) {if (sendChannel) {var state = sendChannel.readyState;
​if (state === "open") {messageInputBox.disabled = false;messageInputBox.focus();sendButton.disabled = false;disconnectButton.disabled = false;connectButton.disabled = true;} else {messageInputBox.disabled = true;sendButton.disabled = true;connectButton.disabled = false;disconnectButton.disabled = true;}}}

    如果通道状态已经变更为 "open", 意味着我们已经完成了在两对等节点之间建立连接。 相应地用户界面根据状态更新,许用并将输入光标聚焦在text 输入框,以便用户可以立即输入要发送给对方的文本消息, 同时界面许用 "Send" 和 "Disconnect" 按钮(既然它们已经准备好了),禁用"Connect"按钮,既然在已经建立连接的情况下用不着它。

    当连接状态变更为 "closed"时,界面执行相反的操作: 禁用文本输入框和 "Send" 按钮 , 许用"Connect" 按钮, 以便用户在需要时可以打开新的连接,禁用"Disconnect" 按钮,既然没有连接时用不着它。

    另一方面,作为我们例子的remote 节点, 则无视这些状态改变事件, 仅仅是在控制台输出它们:

function handleReceiveChannelStatusChange(event) {if (receiveChannel) {console.log("Receive channel's status has changed to " +receiveChannel.readyState);}}

7.发送消息

    当用户按下 "Send" 按钮,触发我们已建立的该按钮的 click事件处理逻辑,在处理逻辑中调用sendMessage() 方法。 该方法也足够简单:

  function sendMessage() {var message = messageInputBox.value;sendChannel.send(message);
​messageInputBox.value = "";messageInputBox.focus();}

    send方法可以发送String,Blob,ArrayBuffer,ArrayBufferView。

8.接收消息

    当远程通道发生“message”事件时,我们的handleReceiveMessage()方法被调用来处理事件。

  function handleReceiveMessage(event) {var el = document.createElement("p");var txtNode = document.createTextNode(event.data);el.appendChild(txtNode);receiveBox.appendChild(el);}

二、多人画板例子

    参考 【从头到脚】WebRTC + Canvas 实现一个双人协作的共享画板

// 有省略
constructor(canvas, {moveCallback}) {···this.moveCallback = moveCallback || function () {}; // 鼠标移动的回调
}
onmousemove(e) { // 鼠标移动this.isMoveCanvas = true;let endx = e.offsetX;let endy = e.offsetY;let width = endx - this.x;let height = endy - this.y;let now = [endx, endy]; // 当前移动到的位置switch (this.drawType) {case 'line' : {let params = [this.last, now, this.lineWidth, this.drawColor];this.moveCallback('line', ...params);this.line(...params);}...
moveCallback(...arr) { // 同步到对方this.send(arr);
},
send(arr) { // 发送消息if (arr[0] === 'text') {···} else { // 处理数据同步this.channel.send(JSON.stringify(arr));}
}

     页面收到 Callback 通知以后,直接调用 send 方法,将数据传递给对方。接收到数据后,调用封装类相应方法进行绘制。

handleChannel(channel) { // 处理 channel···channel.onmessage = (e) => { // 收到消息 普通消息类型是 对象if (Array.isArray(JSON.parse(e.data))) { // 如果收到的是数组,进行结构let [type, ...arr] = JSON.parse(e.data);this.palette[type](...arr); // 调用相应方法} else {this.messageList.push(JSON.parse(e.data)); // 接收普通消息}// console.log('channel onmessage', e.data);};
}
```·
                
            

相关内容

热门资讯

幼儿园毕业典礼老师代表发言稿 2022幼儿园毕业典礼老师代表发言稿(通用10篇)  在生活中,我们使用上发言稿的情况与日俱增,发言...
最新小学生广播稿 最新小学生广播稿  通过无线电波传送节目的称无线广播,通过导线传送节目的称有线广播。下面,小编为大家...
初中语文课文《白兔和月亮》说... 初中语文课文《白兔和月亮》说课稿  下面是人教版语文七年级上册课文《白兔和月亮》说课稿,初中语文课文...
民间故事《彼得与狼》说课稿 民间故事《彼得与狼》说课稿  实践证明,说课活动有效地调动了教师投身教学改革,学习教育理论,钻研课堂...
儿童节目主持人讲话稿 儿童节目主持人讲话稿(精选10篇)  在现实社会中,我们使用上讲话稿的情况与日俱增,讲话稿可以起到整...
伤仲永说课稿 伤仲永说课稿范文  作为一名教学工作者,有必要进行细致的说课稿准备工作,借助说课稿可以更好地组织教学...
领导的讲话稿 领导的讲话稿(精选31篇)  随着社会不断地进步,我们都可能会用到讲话稿,讲话稿一般是开会前或出席重...
信客说课稿 信客说课稿  说教材:  《信客》是人教版语文八年级上册第二单元的一篇略读课文,本单元叙事性作品写的...
《看电视》说课稿 《看电视》说课稿  《看电视》是第二单元第一课。本课由一幅图、一首儿歌组成,其指导思想是通过看图辅助...
《画杨桃》优秀说课稿 人教版《画杨桃》优秀说课稿  《画杨桃》是一篇熟悉得不能再熟悉的老课文了,我们曾经不止一次地教过、听...
新教师代表开训讲话 新教师代表开训讲话新教班开训讲话稿尊敬的各位领导、老师:大家好!我是 。今天,能在这里代表新教师发言...
浅说课前新闻评说 浅说课前新闻评说范文  在我们政治课教学中,课前五分钟采用新闻发布与评说的方式,即让学生自行选择一段...
受助学生代表发言稿 受助学生代表发言稿(精选15篇)  在当下社会,用到发言稿的地方越来越多,发言稿可以提高发言人的自信...
优秀团员代表发言稿 优秀团员代表发言稿范文  现如今,发言稿的使用越来越广泛,发言稿特别注重结构清楚,层次简明。相信写发...
中国古代雕塑欣赏陶俑说课稿 中国古代雕塑欣赏陶俑说课稿范文  在教学工作者开展教学活动前,时常需要用到说课稿,说课稿是进行说课准...
十八岁成人礼发言稿 十八岁成人礼发言稿(通用5篇)  在现在的社会生活中,发言稿对我们的作用越来越大,发言稿是一种实用性...
学校揭牌仪式致辞 学校揭牌仪式致辞范文(精选11篇)  在社会一步步向前发展的今天,用到讲话稿的地方越来越多,讲话稿具...
学生会副主席就职发言稿 学生会副主席就职发言稿范文(通用6篇)  在快速变化和不断变革的新时代,发言稿的使用频率越来越高,发...
100米加油稿 100米加油稿(通用17篇)  在学习、工作生活中,我们都不可避免地要接触到加油稿,借助加油稿往往可...
学习经验交流发言稿 学习经验交流发言稿一年级的学弟学妹们:你们好!上周日晚上,学校通知我让我来给大家做学习经验交流,我听...