WebRTC - 发送消息
现在让我们创建一个简单的示例。首先,通过"节点服务器"运行我们在"信令服务器"教程中创建的信令服务器。
页面上将有三个文本输入,一个用于登录,一个用于用户名,一个用于我们想要发送给对方的消息。创建一个 index.html 文件并添加以下代码 −
<html lang = "en"> <head> <meta charset = "utf-8" /> </head> <body> <div> <input type = "text" id = "loginInput" /> <button id = "loginBtn">Login</button> </div> <div> <input type = "text" id = "otherUsernameInput" /> <button id = "connectToOtherUsernameBtn">Establish connection</button> </div> <div> <input type = "text" id = "msgInput" /> <button id = "sendMsgBtn">Send text message</button> </div> <script src = "client.js"></script> </body> </html>
我们还添加了三个按钮,分别用于登录、建立连接和发送消息。现在创建一个 client.js 文件并添加以下代码 −
var connection = new WebSocket('ws://localhost:9090'); 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; //当用户点击登录按钮时 loginBtn.addEventListener("click", function(event) { name = loginInput.value; if(name.length > 0) { send({ type: "login", name: name }); } }); //处理来自服务器的消息 connection.onmessage = function (message) { console.log("Got message", message.data); var data = JSON.parse(message.data); 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; } }; //当用户登录时 function onLogin(success) { if (success === false) { alert("oops...try a different username"); } else { //创建我们的 RTCPeerConnection 对象 var configuration = { "iceServers": [{ "url": "stun:stun.1.google.com:19302" }] }; myConnection = new webkitRTCPeerConnection(configuration, { optional: [{RtpDataChannels: true}] }); 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 }); } }; openDataChannel(); } }; connection.onopen = function () { console.log("Connected"); }; connection.onerror = function (err) { console.log("Got error", err); }; // 以 JSON 格式发送消息的别名 function send(message) { if (connectedUser) { message.name = connectedUser; } connection.send(JSON.stringify(message)); };
您可以看到我们建立了与信令服务器的套接字连接。当用户单击登录按钮时,应用程序会将其用户名发送到服务器。如果登录成功,应用程序将创建 RTCPeerConnection 对象并设置 onicecandidate 处理程序,该处理程序将所有找到的 icecandidate 发送到另一个对等体。它还运行 openDataChannel() 函数,该函数创建一个数据通道。请注意,在创建 RTCPeerConnection 对象时,如果您使用的是 Chrome 或 Opera,则构造函数中的第二个参数(可选)[{RtpDataChannels: true}] 是必需的。下一步是创建对另一个对等体的报价。将以下代码添加到您的 client.js 文件中−
//与另一个用户建立对等连接 connectToOtherUsernameBtn.addEventListener("click", function () { var otherUsername = otherUsernameInput.value; connectedUser = otherUsername; if (otherUsername.length > 0) { //make an offer myConnection.createOffer(function (offer) { console.log(); send({ type: "offer", offer: offer }); myConnection.setLocalDescription(offer); }, function (error) { alert("An error has occurred."); }); } }); //当有人想打电话给我们时 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"); }); } //当另一个用户回答我们的提议时 function onAnswer(answer) { myConnection.setRemoteDescription(new RTCSessionDescription(answer)); } //when we got ice candidate from another user function onCandidate(candidate) { myConnection.addIceCandidate(new RTCIceCandidate(candidate)); }
您可以看到,当用户单击"建立连接"按钮时,应用程序会向另一个对等点发出 SDP 请求。我们还设置了 onAnswer 和 onCandidate 处理程序。最后,让我们实现创建数据通道的 openDataChannel() 函数。将以下代码添加到您的 client.js 文件中 −
//创建数据通道 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); }; } //当用户点击发送消息按钮时 sendMsgBtn.addEventListener("click", function (event) { console.log("send message"); var val = msgInput.value; dataChannel.send(val); });
在这里,我们为连接创建数据通道,并为"发送消息"按钮添加事件处理程序。现在在两个选项卡中打开此页面,使用两个用户登录,建立连接,然后尝试发送消息。您应该在控制台输出中看到它们。请注意,上述示例是在 Opera 中测试的。
现在您可能会看到 RTCDataChannel 是 WebRTC API 中非常强大的部分。此对象还有许多其他用例,例如点对点游戏或基于 torrent 的文件共享。