如何确定WebRTC数据通道的数据已发送?

3

我正在尝试使用WebRTC编写聊天应用程序,可以使用以下代码将消息通过dataChannel发送:

const peerConnection = new RTCPeerConnection();

const dataChannel =
  peerConnection.createDataChannel("myLabel", dataChannelOptions);

dataChannel.onerror = (error) => {
  console.log("Data Channel Error:", error);
};

dataChannel.onmessage = (event) => {
  console.log("Got Data Channel Message:", event.data);
};

dataChannel.onopen = () => {
  dataChannel.send("Hello World!");
};

dataChannel.onclose = () => {
  console.log("The Data Channel is Closed");
};

使用dataChannel.send()可以正确地通过数据通道发送数据。但我想知道是否有办法确定发送的消息是否已经被成功地传递到另一端?
1个回答

5
这个最简单的答案是:发送一个回复。
但是如果您使用一个有序可靠的数据通道(默认情况下),您可能不需要发送回复。
有序可靠的数据通道
使用其中之一,您可以通过等待缓冲区大小减小来确定消息已发送:

const pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();
const channel = pc1.createDataChannel("chat");

chat.onkeypress = async e => {
  if (e.keyCode != 13) return;

  const before = channel.bufferedAmount;
  channel.send(chat.value);

  const after = channel.bufferedAmount;
  console.log(`Queued ${after - before} bytes`);

  channel.bufferedAmountLowThreshold = before; // set floor trigger and wait
  await new Promise(r => channel.addEventListener("bufferedamountlow", r));

  console.log(`Sent ${after - channel.bufferedAmount} bytes`);
  chat.value = "";
};

pc2.ondatachannel = e => e.channel.onmessage = e => console.log(`> ${e.data}`);
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
pc1.oniceconnectionstatechange = e => console.log(pc1.iceConnectionState);
pc1.onnegotiationneeded = async e => {
  await pc1.setLocalDescription(await pc1.createOffer());
  await pc2.setRemoteDescription(pc1.localDescription);
  await pc2.setLocalDescription(await pc2.createAnswer());
  await pc1.setRemoteDescription(pc2.localDescription);
}
Chat: <input id="chat"><br>

由于通道是可靠的,因此在消息被接收之前,它不会停止发送该消息。

由于通道是有序的,所以在接收到此消息之前,它不会发送第二个消息。

这使您可以连续发送一堆消息而无需等待回复。只要bufferedAmount保持下降,您就知道正在发送和接收。

简而言之,要确定已接收到消息,请发送第二条消息或让另一方发送回复。

不可靠的数据通道

如果您使用的是不可靠的数据通道,则发送回复是唯一的方法。但是,由于无法保证回复是否能够返回,这可能会产生错误的负面影响,在接收端产生重复的消息。

单向不可靠,另一方面是可靠的

使用negotiated构造函数参数,可以创建一个数据通道,在一个方向上不可靠,但在另一个方向上可靠。这可以用来解决不可靠的回复,避免接收端(pc2)上的重复消息。

dc1 = pc1.createDataChannel("chat", {negotiated: true, id: 0, maxRetransmits: 0});
dc2 = pc2.createDataChannel("chat", {negotiated: true, id: 0});

1
注意,它会覆盖bufferedAmountLowThreshold。在实际的日志中使用多个消息之前,还需要进行一些工作。但我希望它能说明问题。 - jib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接