RTCDataChannel 发送方法不发送数据

RTCDataChannel send method not sending data

我在使用 RTCDataChannel 时遇到了一个奇怪的问题。

我正在做一些关于 WebRTC 的研究,我已经开始使用 WebRTC audio/video 聊天了。现在我想使用 RTCDataChannel 添加文本聊天和文件共享。

我创建了这样的 RTCDataChannel:

var dataChannelOptions = {
    reliable: true,
    maxRetransmitTime: "2000"
};

dataChannel = yourConnection.createDataChannel("testDataChannel", dataChannelOptions);

dataChannel.onerror = function (error) {
    console.log("dataChannel.OnError:", error);
};

dataChannel.onmessage = function (event) {
    console.log("dataChannel.OnMessage:", event);
};

dataChannel.onopen = function (event) {
    console.log("dataChannel.OnOpen", event);
    dataChannel.send("Hello World!");
};

dataChannel.onclose = function (event) {
    console.log("dataChannel.OnClose", event);
};

我在双方都收到的唯一信息是 dataChannel.onopen 第一行的日志。我没有收到来自 dataChannel.onmessage.

的日志

没有错误..

当我手动调用dataChannel.send时结果是一样的

测试于:
Google Chrome (50.0.2661.94)
火狐 (45.0.2)

有人可以帮忙吗?

这是人们常犯的错误,您在两个浏览器上都创建了数据通道,但都没有接受,您需要使用 RTCPeerConnection 的 ondatachannel 事件并设置监听器

我遇到了同样的问题。根据 RTCDataChannel 文档,您应该处理 Peer Connection 对象上的回调以接收数据通道上的数据。下面的代码可能会有帮助:

第 1 步:定义回调处理程序:

  var handleDataChannelOpen = function (event) {
    console.log("dataChannel.OnOpen", event);
    dataChannel.send("Hello World!");
  };

  var handleDataChannelMessageReceived = function (event) {
    console.log("dataChannel.OnMessage:", event);
  };

  var handleDataChannelError = function (error) {
    console.log("dataChannel.OnError:", error);
  };

  var handleDataChannelClose = function (event) {
    console.log("dataChannel.OnClose", event);
  };

  var handleChannelCallback = function (event) {
     dataChannel = event.channel;
     dataChannel.onopen = handleDataChannelOpen;
     dataChannel.onmessage = handleDataChannelMessageReceived;
     dataChannel.onerror = handleDataChannelError;
     dataChannel.onclose = handleDataChannelClose;
  };

第 2 步:创建 RTC 对等连接:

  var pc = new RTCPeerConnection();
  pc.ondatachannel = handleChannelCallback;

第 3 步:创建数据通道:

  var dataChannel = pc.createDataChannel('dataChannelName', {});

  dataChannel.onopen = handleDataChannelOpen;
  dataChannel.onmessage = handleDataChannelMessageReceived;
  dataChannel.onerror = handleDataChannelError;
  dataChannel.onclose = handleDataChannelClose;

在您的代码中,您只需添加 ondatachannel 回调处理程序即可接收数据。

我认为最大的误解,至少对我来说,是每个客户端都需要保留对 两个 频道的引用(如果错误请纠正我,因为它不会感觉完全正确)。一个用于发送,一个用于接收。这基本上就是@Nikhil 的回答所显示的内容。他为处理程序创建命名函数,以便使用它们两次。

另请注意,您可以在 peerConnection 实例化后立即定义数据连接。我读过相互矛盾的说法,说你必须只从呼叫者那里做,或者只有在连接准备好之后。也许旧版本的 WebRTC 确实如此,但这适用于当前 chrome(截至 2017 年 10 月的任何版本)。

let pc = new RTCPeerConnection({"iceServers": [{"url": "stun:stun.l.google.com:19302"}]});

const handleDataChannelOpen = (event) =>{
    console.log("dataChannel.OnOpen", event);
    sendChannel.send("Hello World!");
};

const handleDataChannelMessageReceived = (event) =>{
    console.log("dataChannel.OnMessage:", event);
};

const handleDataChannelError = (error) =>{
    console.log("dataChannel.OnError:", error);
};

const handleDataChannelClose = (event) =>{
    console.log("dataChannel.OnClose", event);
};


let sendChannel = pc.createDataChannel('text', {});
sendChannel.onopen = handleDataChannelOpen;
sendChannel.onmessage = handleDataChannelMessageReceived;
sendChannel.onerror = handleDataChannelError;
sendChannel.onclose = handleDataChannelClose;


pc.ondatachannel = (event) =>{
    console.log("on data channel")
    let receiveChannel = event.channel;
    receiveChannel.onopen = handleDataChannelOpen;
    receiveChannel.onmessage = handleDataChannelMessageReceived;
    receiveChannel.onerror = handleDataChannelError;
    receiveChannel.onclose = handleDataChannelClose;

    let button = document.getElementById(this.id + "-submit");
    button.onclick = () =>{
        receiveChannel.send("hello from " + this.id)
    };
};

//... do your connection with servers

这是有效的客户端代码,我在这里分享,可能对某人有所帮助。如果对您有帮助,请不胜感激:

            var connection = new WebSocket('wss://127.0.0.1:3000'); 
            var name = "";

            var loginInput = document.querySelector('#loginInput'); 
            var loginBtn = document.querySelector('#loginBtn'); 

            var otherUsernameInput = document.querySelector('#otherUsernameInput'); 
            var connectToOtherUsernameBtn = document.querySelector('#connectToOtherUsernameBtn'); 
            var msgInput = document.querySelector('#msgInput'); 
            var sendMsgBtn = document.querySelector('#sendMsgBtn'); 
            var connectedUser, myConnection, dataChannel;

            //when a user clicks the login button 
            loginBtn.addEventListener("click", function(event) { 
               name = loginInput.value; 

               if(name.length > 0) { 
                  send({ 
                     type: "login", 
                     name: name 
                  }); 
               } 
            });

            //handle messages from the server 
            connection.onmessage = function (message) {
            //    if(message)
                var data = JSON.parse(message.data);
                console.log("Got message", data.type);
               switch(data.type) { 
                  case "login": 
                     onLogin(data.success); 
                     break; 
                  case "offer": 
                     onOffer(data.offer, data.name); 
                     break; 
                  case "answer":
                     onAnswer(data.answer); 
                     break; 
                  case "candidate": 
                     onCandidate(data.candidate); 
                     break; 
                  default: 
                     break; 
               } 
            }; 

            //when a user logs in 
            function onLogin(success) { 

               if (success === false) { 
                  alert("oops...try a different username"); 
               } else { 
                  //creating our RTCPeerConnection object 
                  var configuration = { 
                     "iceServers": [{ "url": "stun:stun.1.google.com:19302" }] 
                  }; 

                  myConnection = new RTCPeerConnection(configuration); 

                  console.log("RTCPeerConnection object was created"); 
                  console.log(myConnection); 

                  //setup ice handling 
                  //when the browser finds an ice candidate we send it to another peer 
                  myConnection.onicecandidate = function (event) { 

                     if (event.candidate) { 
                        send({ 
                           type: "candidate", 
                           candidate: event.candidate 
                        });
                     } 
                  }; 
                  myConnection.ondatachannel = function (event) {
                      var receiveChannel = event.channel;
                      receiveChannel.onmessage = function (event) {
                          console.log("ondatachannel message:", event.data);
                      };
                  }; 

                  openDataChannel();
                  console.log("DataChannel Opened..");

               } 
            };

            connection.onopen = function () { 
               console.log("Connected"); 
            }; 

            connection.onerror = function (err) { 
               console.log("Got error", err); 
            };

            // Alias for sending messages in JSON format 
            function send(message) { 
               if (connectedUser) { 
                  message.name = connectedUser; 
               }

               connection.send(JSON.stringify(message)); 
            };

            //setup a peer connection with another user 
            connectToOtherUsernameBtn.addEventListener("click", function () {

               var otherUsername = otherUsernameInput.value;
               connectedUser = otherUsername;

               if (otherUsername.length > 0) { 
                  //make an offer 
                  myConnection.createOffer(function (offer) { 
                     console.log(offer); 

                     send({ 
                        type: "offer", 
                        offer: offer 
                     }); 

                     myConnection.setLocalDescription(offer); 
                  }, function (error) { 
                     alert("An error has occurred."); 
                  }); 
               } 
            });

            //when somebody wants to call us 
            function onOffer(offer, name) { 
               connectedUser = name; 
               myConnection.setRemoteDescription(new RTCSessionDescription(offer));

               myConnection.createAnswer(function (answer) { 
                  myConnection.setLocalDescription(answer); 

                  send({ 
                     type: "answer", 
                     answer: answer 
                  }); 

               }, function (error) { 
                  alert("oops...error"); 
               }); 
            }

            //when another user answers to our offer 
            function onAnswer(answer) { 
               myConnection.setRemoteDescription(new RTCSessionDescription(answer)); 
            }

            //when we got ice candidate from another user 
            function onCandidate(candidate) { 
               myConnection.addIceCandidate(new RTCIceCandidate(candidate)); 
            }


            //creating data channel 
            function openDataChannel() { 

               var dataChannelOptions = { 
                  reliable:true 
                };

               dataChannel = myConnection.createDataChannel("myDataChannel", dataChannelOptions);

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

               dataChannel.onmessage = function (event) { 
                  console.log("Got message:", event.data); 
               };  
            }

            //when a user clicks the send message button 
            sendMsgBtn.addEventListener("click", function (event) { 
               console.log("send message");
               var val = msgInput.value; 
               dataChannel.send(val); 
            });