RTCDataChannel接口表示两个对等方之间的双向数据通道。每个数据通道都关联个RTCPeerConnection对等连接,每个对等连接理论上最多可以有65534个数据通道。RTCDataChannel接口定义如下面的代码清单所示。
//RTCDataChannel接口定义
[Exposed=window]
interface RTCDataChannel : EventTarget {
readonly attribute USVString label;
readonly attribute boolean ordered;
readonly attribute unsigned short? maxPacketLifeTime;
readonly attribute unsigned short? maxRetransmits;
readonly attribute USVString protocol;
readonly attribute boolean negotiated;
readonly attribute unsigned short? id;
readonly attribute RTCDataChannelState readyState;
readonly attribute unsigned long bufferedAmount;
[EnforceRange] attribute unsigned long bufferedAmountLowThreshold;
attribute EventHandler onopen;
attribute EventHandler onbufferedamountlow;
attribute EventHandler onerror;
attribute EventHandler onclosing;
attribute EventHandler onclose;
void close();
attribute EventHandler onmessage;
attribute DOMString binaryType;
void send(USVString data);
void send(Blob data);
void send(ArrayBuffer data);
void send(ArrayBufferView data);
};
RTCDataChannel的属性说明如下表所示。
| RTCDataChannel 的属性说明 | ||
| 属性 | 类型 | 说明 |
| label | 字符串 | 只读属性,通道名称 |
| ordered | 布尔 | 只读属性,是否保持发包顺序 |
| maxPacketLifeTime | 数值 | 只读属性,发送消息间隔的最大毫秒数 |
| maxRetransmits | 数值 | 只读属性,发送消息失败后的重传次数 |
| protocol | 字符串 | 只读属性,数据通道使用的子协议名称 |
| negotiated | 布尔 | 只读属性,带内协商还是带外协商 |
| id | 数值 | 只读属性,数据通道的唯一标识 |
| readyState | RTCDataChannelState | 只读属性,数据通道的状态 |
| bufferedAmount | 数值 | 只读属性,等待发送的缓存队列长度,单位是字节 |
| bufferedAmountLowThreshold | 数值 |
可读写,用于设置低位缓存的阈值,当缓存队列减少到该阈值时,触发事件 bufferedamountlow。 该属性的初始值是0,应用程序可以随时改变该属性值 |
| binaryType | 字符串 | 可读写,用于控制如何发送二进制数据,可设置为blob或arraybuffer |
readyState 属性表示当前数据通道的状态,是 RTCDataChannelState 枚举类型,定义如下面的代码清单所示。
//RTCDataChannelState的定义
enum RTCDataChannelstate {
"connecting",
"open",
"closing",
"closed"
};
RTCDataChannelState 包含如下枚举值。
该方法用于关闭数据传输通道,每一个对等方都可以调用该方法关闭数据通道。关闭连接是异步进行的,通过监听 close 事件可以获取关闭完成的通知。
调用该方法将触发以下动作。
//close()方法示例
const pc = new RTCPeerConnection();
const dc = pc.createDataChannel("my channel");
dc.onmessage = (event) => {
console.log("received:"+ event.data);
dc.close();
};
dc.onopen = () => {
console.log("datachannel open");
};
dc.onclose = () => {
console.log("datachannel close");
};
该方法通过数据通道将数据发送到对等端,调用语法如下。
RTCDataChannel.send(data);
参数:data,要发送的数据,类型可以是字符串、Blob、ArrayBuffer 或 ArrayBufferView。发送数据的大小受 RTCSctpTransport.maxMessageSize 的限制。
返回值:无。
异常值:如果该方法调用失败,返回异常值如下表所示。
| send()方法异常值 | |
| 异常值 | 说明 |
| InvalidStateError | 当前数据通道不是 open 状态 |
| TypeError | 发送数据的大小超出了 maxMessageSize |
| OperationError | 当前缓存队列满了 |
//send()方法示例
const pc = new RTCPeerConnection(options);
const channel = pc.createDataChannel("chat");
channel.onopen= (event) => {
let obj = {
"message" : msg,
"timestamp" : new Date()
};
channel.send(JSON.stringify(obj));
}
当缓存队列字节数从高于 bufferedAmountLowThreshold 降低到 bufferedAmountLowThreshold 之下时触发 bufferedamountlow 事件,对应事件句柄 onbufferedamountlow,事件类型为 Event。
通常情况下,当数据通道的缓存队列字节数低于设定值时,意味着数据正常发送,没有堆积,这时候可以继续向缓存队列追加数据。下面的代码清单演示了这个过程。
//onbufferedamountlow事件句柄示例
let pc = new RTCPeerConnection();
let dc = pc.createDataChannel("SendFile");
let source = /* source data object */
dc.bufferedAmountLowThreshold = 65536;
pc.onbufferedamountlow = ev => {
if (source.position <= source.length) {
dc.send(source.readFile(65536));
}
};
当数据通道被关闭时触发 close 事件,对应事件句柄 onclose,事件类型为 Event。close() 方法执行了关闭的动作,关闭过程是异步的,可在 close 事件中获取事件结果。
当数据通道出现错误时,触发error事件,对应事件柄onerror,事件类型为 RTCErrorEvent。
//onerror事件句柄示例
dc.onerror = ev => {
const err = ev.error;
console.error("WebRTC error: ", err.message);
switch(err.errorDetail) {
case ""sdp-syntax-error":
console.error("SDP syntax error in line ", err.sdpLineNumber);
break;
case "idp-load-failure":
console.error(" Identity provider load failure: HTTP error ", err.httpRequestStatusCode);
break;
case "sctp-failure":
console.error(" SCTP failure: ", err.sctpCauseCode);
break;
case "dtls-failure":
if (err.receivedAlert) {
console.error(" Received DLTS failure alert: ", err.receivedAlert);
}
if (err.sentAlert) {
console.error(" Sent DLTS failure alert: ", err.sendAlert);
}
break;
}
console.error(" Error in file ", err.filename, " at line ", err.lineNumber, ", column ", err.columnNumber);
}
当从对等端收到消息时,触发message事件,对应事件柄onmessage。事件类型为MessageEvent,它代表目标对象收到的消息事件,也用于WebSocket的消息事件中。MessageEvent的定义如下面的代码清单所示。
//MessageEvent的定义
interface MessageEvent : Event {
constructor(DOMString type, optional MessageEventInit eventInitDict = {});
readonly attribute any data;
readonly attribute USVString origin;
readonly attribute DOMString lastEventId;
readonly attribute MessageEventSource? source;
readonly attribute FrozenArray<MessagePort> ports;
void initMessageEvent(DOMString type, optional boolean bubbles = false,
optional boolean cancelable = false, optional any data = null, optional
USVString origin = "", optional DOMString lastEventId = "", optional
MessageEventSource? source = null, optional sequence<Messageport> ports = []);
};
dictionary MessageEventInit : EventInit {
any data = null;
USVString origin = "";
DOMString lastEventId = "";
MessageEventSource? source = null;
sequence<MessagePort> ports = [];
};
由于我们只需要使用 MessageEvent 的属性,所以只对属性进行说明。
| MessageEvent的属性说明 | ||
| 属性 | 类型 | 说明 |
| data | 任意 | 接收到的数据,可以为任意类型 |
| origin | 字符串 | 描述消息发送源 |
| lastEventId | 字符串 | 代表当前事件的ID |
| source | MessageEventSource | 消息发送源对象 |
| ports | MessagePort[] | 发送消息使用的端口 |
data属性代表接收到的数据,是message事件必须要使用的属性。下面的代码清单演示了onmessage事件句柄的使用方法,该示例将接收到的消息展示到页面中。
//onmessage事件句柄示例
dc.onmessage = ev => {
let newParagraph = document.createElement("p");
let textNode = document.createTextNode(event.data);
newParagraph.appendChild(textNode);
document.body.appendChild(newParagraph);
}
当用于收发数据的底层传输通道被打开且可用时,触发open事件,对应事件句柄onopen,事件类型为Event。