使用信令实现Hello World WebRTC DataChannel示例 [英] Working Hello World WebRTC DataChannel Examples with Signaling Implemented
问题描述
目的是成为社区Wiki 帖子,保持最新,因此对使用WebRTC DataChannel实现JSON消息浏览器到浏览器(p2p)的通信感兴趣的开发人员有简单而实用的示例。
WebRTC DataChannels是实验性的,仍在选秀中。目前网络似乎是过时的WebRTC示例的雷区,如果开发人员正在尝试学习RTCDataChannel API,那就更是如此。
简单而实用的1页示例今天在WebRTC 兼容的浏览器上工作似乎很难找到。例如,一些示例忽略了信号实现,其他仅适用于单个浏览器(例如Chrome-Chrome),很多已过时,其他如此复杂,它们为入门创造了障碍。
请发布符合以下条件的示例(如果是不符合请注明):
- 客户端代码为1页(200行或更少)
- 服务器端代码为1页,引用了技术(例如node.js,php,python等)。
- 实现了信令机制并引用了协议技术(例如WebSockets,长轮询, GCM 等。)
- 跨浏览器运行的代码(Chrome,Firefox,Opera和/或 Bowser )
- 最小选项,错误处理, abstraction 等 - 意图是一个基本的例子
这是一个使用HTML5 WebSockets进行信令和node.js后端的工作示例
<信令技术:
WebSockets
客户端:
纯html / javascript
服务器:
node.js
, ws
最后一次测试:
Firefox 40.0.2
, Chrome 44.0.2403.157 m
, Opera 31.0.1889.174
客户端代码:
< html>
< head>
< / head>
< body>
< p id ='msg'>在其他浏览器中点击以下内容windows< / p>
< button type ='button'onclick ='init(false)'>我是Answerer Peer(点击第一个)< / button>
< button type ='button 'onclick ='init(true)'> I AM Offerer Peer< / button>
< script>
(function(){
var offererId ='Gandalf', //注意:客户端ID冲突可能发生
answererId ='Saruman',//没有websocket清理代码存在
ourId,peerId,
RTC_IS_MOZILLA = !! window.mozRTCPeerConnection,
RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection,
RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription,
RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate,
rtcpeerconn = new RTCPeerConnection(
{iceServers:[{'url':'stun:stun.services.mozilla.com'},{'url':'stun:stun.l .google.com:19302'}]},
{可选:[{RtpDataChannels:false}]}
),
rtcdatachannel,
websocket = new WebSocket('ws: //'+ window.location.hostname +':8000'),
comready,onerror;
window.init = function(weAreOfferer){
ourId = weAreOfferer? offererId:answererId;
peerId = weAreOfferer? answererId:offererId;
websocket.send(JSON.stringify({
inst:'init',
id:ourId
}));
if(weAreOfferer){
rtcdatachannel = rtcpeerconn.createDataChannel(offererId + answererId);
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
rtcpeerconn.createOffer(function(offer){
rtcpeerconn.setLocalDescription(offer,function(){
var output = offer.toJSON();
if(b) typeof output ==='string')output = JSON.parse(output); // normalize:RTCSessionDescription.toJSON返回FF中的json str,但Chrome中的json obj
websocket.send(JSON) .stringify({
inst:'send',
peerId:peerId,
message:output
}));
},onerror);
},onerror);
}
};
rtcpeerconn.ondatachannel = function(event){
rtcdatachannel = event.channel;
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
};
websocket.onmessage = function(输入){
var message = JSON.parse(input.data);
if(message.type && message.type ==='offer'){
var offer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(offer,function(){
rtcpeerconn.createAnswer(function(answer){
rtcpeerconn.setLocalDescription(answer,function(){
var output = answer.toJSON();
if(typeof output ==='string')output = JSON.parse(output); // normalize:RTCSessionDescription.toJSON返回FF中的json str,但是json obj in Chrome
websocket.send(JSON.stringify({
inst:'send',
peerId:peerId,
message:output
})) ;
},onerror);
},onerror);
},onerror);
} else if(message.type && message.type ==='answer'){
var answer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(answer,function(){/ *处理程序需要但我们无关* /},onerror);
}否则if(rtcpeerconn.remoteDescription){
//忽略冰候选者,直到远程描述被设置为
rtcpeerconn.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};
rtcpeerconn.onicecandidate = function(event){
if(!event ||!event.candidate)return;
websocket.send(JSON.stringify({
inst:'send',
peerId:peerId,
message:{candidate:event.candidate}
}) );
};当RTC信令完成且RTCDataChannel准备就绪时调用
/ ** * /
comready = function(){
rtcdatachannel.send('hello world!');
rtcdatachannel.onmessage = function(event){
document.getElementById('msg')。innerHTML ='RTCDataChannel peer'+ peerId +'say:'+ event.data;
}
};
/ **全局错误函数* /
onerror = websocket.onerror = function(e){
console.log('====== WEBRTC ERROR == ====',参数);
document.getElementById('msg')。innerHTML ='====== WEBRTC ERROR ======< br>'+ e;
抛出新错误(e);
};
})();
< / script>
< / body>
< / html>
服务器端代码:
var server = require('http')。createServer(),
express = require('express'),
app = express(),
WebSocketServer = require('ws')。Server,
wss = new WebSocketServer({server:server,port:8000 });
app.use(express.static(__ dirname +'/ static')); //客户端代码进入静态目录
var clientMap = {};
wss.on('connection',function(ws){
ws.on('message',function(inputStr){
var input = JSON.parse(inputStr) );
if(input.inst =='init'){
clientMap [input.id] = ws;
} else if(input.inst =='send'){
clientMap [input.peerId] .send(JSON.stringify(input.message));
}
});
});
server.on('request',app);
server.listen(80,YOUR_HOSTNAME_OR_IP_HERE,function(){console.log('Listening on'+ server.address()。port)});
The intent is for this to become a Community Wiki post that is kept up-to-date so developers interested in implementing communication of JSON messages browser-to-browser (p2p) with WebRTC DataChannels have simple yet functional examples.
WebRTC DataChannels are experimental and still in draft. It seems that currently the web is a minefield of outdated WebRTC examples and even more so if a developer is trying to learn the RTCDataChannel API.
Simple yet functional 1-page examples that work today across WebRTC compliant browsers seem very difficult to find. For example, some examples leave out a signaling implementation, others only work for a single browser (e.g. Chrome-Chrome), many are outdated due to recent API changes, and others are so complex they create a barrier to getting started.
Please post examples that meet the following criteria (if something is not met please specify):
- Client-side code is 1-page (200 lines or less)
- Server-side code is 1-page and technology is referenced (e.g. node.js, php, python, etc.)
- Signaling mechanism is implemented and protocol technology is referenced (e.g. WebSockets, long polling, GCM, etc.)
- Working code that runs cross-browser (Chrome, Firefox, Opera, and/or Bowser)
- Minimal options, error handling, abstraction, etc. -- the intent is an elementary example
Here is a working example that uses HTML5 WebSockets for signaling and a node.js backend
signaling technology: WebSockets
client: pure html/javascript
server: node.js
, ws
last tested on: Firefox 40.0.2
, Chrome 44.0.2403.157 m
, Opera 31.0.1889.174
client-side code:
<html>
<head>
</head>
<body>
<p id='msg'>Click the following in different browser windows</p>
<button type='button' onclick='init(false)'>I AM Answerer Peer (click first)</button>
<button type='button' onclick='init(true)'>I AM Offerer Peer</button>
<script>
(function() {
var offererId = 'Gandalf', // note: client id conflicts can happen
answererId = 'Saruman', // no websocket cleanup code exists
ourId, peerId,
RTC_IS_MOZILLA = !!window.mozRTCPeerConnection,
RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection,
RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.msRTCSessionDescription,
RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.msRTCIceCandidate,
rtcpeerconn = new RTCPeerConnection(
{iceServers: [{ 'url': 'stun:stun.services.mozilla.com'}, {'url': 'stun:stun.l.google.com:19302'}]},
{optional: [{RtpDataChannels: false}]}
),
rtcdatachannel,
websocket = new WebSocket('ws://' + window.location.hostname + ':8000'),
comready, onerror;
window.init = function(weAreOfferer) {
ourId = weAreOfferer ? offererId : answererId;
peerId = weAreOfferer ? answererId : offererId;
websocket.send(JSON.stringify({
inst: 'init',
id: ourId
}));
if(weAreOfferer) {
rtcdatachannel = rtcpeerconn.createDataChannel(offererId+answererId);
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
rtcpeerconn.createOffer(function(offer) {
rtcpeerconn.setLocalDescription(offer, function() {
var output = offer.toJSON();
if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: output
}));
}, onerror);
}, onerror);
}
};
rtcpeerconn.ondatachannel = function(event) {
rtcdatachannel = event.channel;
rtcdatachannel.onopen = comready;
rtcdatachannel.onerror = onerror;
};
websocket.onmessage = function(input) {
var message = JSON.parse(input.data);
if(message.type && message.type === 'offer') {
var offer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(offer, function() {
rtcpeerconn.createAnswer(function(answer) {
rtcpeerconn.setLocalDescription(answer, function() {
var output = answer.toJSON();
if(typeof output === 'string') output = JSON.parse(output); // normalize: RTCSessionDescription.toJSON returns a json str in FF, but json obj in Chrome
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: output
}));
}, onerror);
}, onerror);
}, onerror);
} else if(message.type && message.type === 'answer') {
var answer = new RTCSessionDescription(message);
rtcpeerconn.setRemoteDescription(answer, function() {/* handler required but we have nothing to do */}, onerror);
} else if(rtcpeerconn.remoteDescription) {
// ignore ice candidates until remote description is set
rtcpeerconn.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};
rtcpeerconn.onicecandidate = function (event) {
if (!event || !event.candidate) return;
websocket.send(JSON.stringify({
inst: 'send',
peerId: peerId,
message: {candidate: event.candidate}
}));
};
/** called when RTC signaling is complete and RTCDataChannel is ready */
comready = function() {
rtcdatachannel.send('hello world!');
rtcdatachannel.onmessage = function(event) {
document.getElementById('msg').innerHTML = 'RTCDataChannel peer ' + peerId + ' says: ' + event.data;
}
};
/** global error function */
onerror = websocket.onerror = function(e) {
console.log('====== WEBRTC ERROR ======', arguments);
document.getElementById('msg').innerHTML = '====== WEBRTC ERROR ======<br>' + e;
throw new Error(e);
};
})();
</script>
</body>
</html>
server-side code:
var server = require('http').createServer(),
express = require('express'),
app = express(),
WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ server: server, port: 8000 });
app.use(express.static(__dirname + '/static')); // client code goes in static directory
var clientMap = {};
wss.on('connection', function (ws) {
ws.on('message', function (inputStr) {
var input = JSON.parse(inputStr);
if(input.inst == 'init') {
clientMap[input.id] = ws;
} else if(input.inst == 'send') {
clientMap[input.peerId].send(JSON.stringify(input.message));
}
});
});
server.on('request', app);
server.listen(80, YOUR_HOSTNAME_OR_IP_HERE, function () { console.log('Listening on ' + server.address().port) });
这篇关于使用信令实现Hello World WebRTC DataChannel示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!