WebRTC实时通信系列教程7 使用Socket.IO搭建信令服务器交换信息
【转载请注明出处: http://blog.csdn.net/leytton/article/details/76831005】
PS:如果本文对您有帮助,请点个赞让我知道哦~
《WebRTC实时通信系列教程》翻译自《Real time communication with WebRTC》
示例代码下载http://download.csdn.net/detail/leytton/9923708
WebRTC实时通信系列教程5 RTCPeerConnection传输视频
WebRTC实时通信系列教程6 使用RTCDataChannel传输数据
WebRTC实时通信系列教程7 使用Socket.IO搭建信令服务器交换信息
一、译文
1、你将学到
- 使用 npm 安装 package.json文件里的项目依赖
- 运行Node服务器并使用node-static模块支持静态资源文件访问.
- 使用 socket.io 在Node上提供消息传输服务.
- 创建房间并传输消息.
完整示例代码在 step-04 目录下.
2、概念
为了建立并维持WebRTC通话, WebRTC 客户端 (peers)之间需要交换元数据:
- Candidate (network) 信息.
- Offer 和 answer 消息提供媒体的信息,如分辨率和编解码器。
也就是说, 在点对点之间传输音视频和数据之前需要交换元数据. 这一过程叫做信令交换(signaling).
在前面的小节中, RTCPeerConnection 对象之间发送和接收数据是在同一页面, 所以信令交换只需要对象之间赋值就实现了元数据传递.
但在实际应用当中, RTCPeerConnections的发送端和接收端是不同的设备, 所以我们需要一种方法在其之间交换元数据.
在这里,我们使用了信令服务器(signaling server): 一个能使WebRTC客户端(peers)之间交换信息的服务器.这些消息是纯文本信息: 序列化的 JavaScript对象.
3、关于应用
在这节中我们将建立一个简单的 Node.js 信令服务器, 使用 Socket.IO 模块和 JavaScript 库进行通信.学会 Node.js 和 Socket.IO 的使用是很有用的, 但在这里不是主要的; 这个消息组件很简单.
选择合适的信令服务器
这里使用 Socket.IO 创建信令服务器.
使用Socket.io能够非常简单地创建消息通信服务, 并且Socket.io 非常适合 WebRTC 信令交换因为它内置了房间('rooms')概念.
生产使用时可能有更好地选择. 另阅 How to Select a Signaling Protocol for Your Next WebRTC Project.
在代码中, Node应用服务端代码在index.js文件中实现, Web客户端代码在 index.html 文件中实现.
Node应用需要实现两个功能.
首先, 它能够进行消息传递:
socket.on('message', function (message) {
log('Got message: ', message);
socket.broadcast.emit('message', message);
});
其次, 它能管理WebRTC视频聊天房间:
if (numClients === 1) {
socket.join(room);
socket.emit('created', room, socket.id);
} else if (numClients === 2) {
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
我们这个简单的WebRTC应用中最多允许两个客户端在同一房间中.
4、HTML和JavaScript代码
index.html文件代码:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="js/main.js"></script>
</body>
</html>
你在页面上看不到任何信息: 浏览器控制台会有日志输出.
js/main.js 文件代码:
'use strict';
var isInitiator;
window.room = prompt("Enter room name:");
var socket = io.connect();
if (room !== "") {
console.log('Message from client: Asking to join room ' + room);
socket.emit('create or join', room);
}
socket.on('created', function(room, clientId) {
isInitiator = true;
});
socket.on('full', function(room) {
console.log('Message from client: Room ' + room + ' is full :^(');
});
socket.on('ipaddr', function(ipaddr) {
console.log('Message from client: Server IP address is ' + ipaddr);
});
socket.on('joined', function(room, clientId) {
isInitiator = false;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
5、在Node服务器运行Socket.IO
在 work 根目录下创建文件 package.json :
{ "name": "webrtc-codelab", "version": "0.0.1", "description": "WebRTC codelab", "dependencies": { "node-static": "0.7.7", "socket.io": "1.2.0" } }
这是一个应用程序清单,告诉Node包管理器(npm)要安装的项目依赖。
在 work 目录下使用以下命令行即可安装项目依赖:
npm install
安装结束后你将看到一下日志:
正如你所看到的, npm
已经把 package.json 文件里定义的项目依赖安装好了.
可能会有警告信息, 但如果有红色的错误信息,可以寻求帮助!
在 work 根目录下创建文件 index.js :(注意不是在js目录中)
'use strict';
var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');
var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
fileServer.serve(req, res);
}).listen(8080);
var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {
// convenience function to log server messages on the client
function log() {
var array = ['Message from server:'];
array.push.apply(array, arguments);
socket.emit('log', array);
}
socket.on('message', function(message) {
log('Client said: ', message);
// for a real app, would be room-only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function(room) {
log('Received request to create or join room ' + room);
var numClients = io.sockets.sockets.length;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
if (numClients === 1) {
socket.join(room);
log('Client ID ' + socket.id + ' created room ' + room);
socket.emit('created', room, socket.id);
} else if (numClients === 2) {
log('Client ID ' + socket.id + ' joined room ' + room);
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
});
socket.on('ipaddr', function() {
var ifaces = os.networkInterfaces();
for (var dev in ifaces) {
ifaces[dev].forEach(function(details) {
if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
socket.emit('ipaddr', details.address);
}
});
}
});
});
在 work 目录下使用以下命令行:
node index.js
在浏览器打开 localhost:8080.
每次你打开这个URL地址, 将被提示输入一个房间名称. 要加入同一个房间,每次选择同一个房间名称,如“foo”.
打开新标签, 再次访问 localhost:8080 . 选择相同的房间名.
在第三个标签中打开 localhost:8080 . 再次选择相同的房间名.
检查每个标签的控制台: 你将会看到上述 JavaScript 代码打印的日志.
6、拓展
- 我们可以选择哪些消息传递机制? 使用纯WebSocket会遇到哪些问题?
- 如果要扩展这个应用会遇到哪些问题? 你能开发一种方法来测试数以千计甚至数以百万计的同时房间请求吗?
- 这个应用使用JavaScript提示输入房间名. 找到一种方法从URL地址来获取房间名. 例如从 localhost:8080/foo 获取房间名
foo
.
7、你学习了
- 使用 npm 安装 package.json文件里的项目依赖
- 运行Node服务器并使用node-static模块支持静态资源文件访问.
- 使用 socket.io 在Node上提供消息传输服务.
- 创建房间并传输消息.
完整示例代码在 step-04 目录下.
8、更多资料
- Socket.io chat-example repo
- WebRTC in the real world: STUN, TURN and signaling
- The term 'signaling' in WebRTC
9、下一节
使用信令传输让两个用户建立P2P连接.
二、原文
摘自https://codelabs.developers.google.com/codelabs/webrtc-web/#5
7. Set up a signaling service to exchange messages
What you'll learn
In this step, you'll find out how to:
- Use
npm
to install project dependencies as specified in package.json - Run a Node server and use node-static to serve static files.
- Set up a messaging service on Node using socket.io.
- Use that to create 'rooms' and exchange messages.
A complete version of this step is in the step-04 folder.
Concepts
In order to set up and maintain a WebRTC call, WebRTC clients (peers) need to exchange metadata:
- Candidate (network) information.
- Offer and answer messages providing information about media, such as resolution and codecs.
In other words, an exchange of metadata is required before peer-to-peer streaming of audio, video, or data can take place. This process is called signaling.
In the previous steps, the sender and receiver RTCPeerConnection objects are on the same page, so 'signaling' is simply a matter of passing metadata between objects.
In a real world application, the sender and receiver RTCPeerConnections run in web pages on different devices, and we need a way for them to communicate metadata.
For this, we use a signaling server: a server that can pass messages between WebRTC clients (peers). The actual messages are plain text: stringified JavaScript objects.
About the app
In this step we'll build a simple Node.js signaling server, using the Socket.IO Node module and JavaScript library for messaging. Experience with Node.js and Socket.IO will be useful, but not crucial; the messaging components are very simple.
Choosing the right signaling server
This codelab uses Socket.IO for a signaling server.
The design of Socket.io makes it straightforward to build a service to exchange messages, and Socket.io is suited to WebRTC signaling because of its built-in concept of 'rooms'.
For a production service, there may be better alternatives. See How to Select a Signaling Protocol for Your Next WebRTC Project.
In this example, the server (the Node application) is implemented in index.js, and the client that runs on it (the web app) is implemented in index.html.
The Node application in this step has two tasks.
First, it acts as a message relay:
socket.on('message', function (message) {
log('Got message: ', message);
socket.broadcast.emit('message', message);
});
Second, it manages WebRTC video chat 'rooms':
if (numClients === 1) {
socket.join(room);
socket.emit('created', room, socket.id);
} else if (numClients === 2) {
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
Our simple WebRTC application will permit a maximum of two peers to share a room.
HTML & JavaScript
Update index.html so it looks like this:
<!DOCTYPE html>
<html>
<head>
<title>Realtime communication with WebRTC</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<h1>Realtime communication with WebRTC</h1>
<script src="/socket.io/socket.io.js"></script>
<script src="js/main.js"></script>
</body>
</html>
You won't see anything on the page in this step: all logging is done to the browser console. (To view the console in Chrome, press Ctrl-Shift-J, or Command-Option-J if you're on a Mac.)
Replace js/main.js with the following:
'use strict';
var isInitiator;
window.room = prompt("Enter room name:");
var socket = io.connect();
if (room !== "") {
console.log('Message from client: Asking to join room ' + room);
socket.emit('create or join', room);
}
socket.on('created', function(room, clientId) {
isInitiator = true;
});
socket.on('full', function(room) {
console.log('Message from client: Room ' + room + ' is full :^(');
});
socket.on('ipaddr', function(ipaddr) {
console.log('Message from client: Server IP address is ' + ipaddr);
});
socket.on('joined', function(room, clientId) {
isInitiator = false;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
Set up Socket.IO to run on Node
For this and the following steps, you'll run Socket.IO on Node.
At the top level of your work directory create a file named package.json with the following contents:
{ "name": "webrtc-codelab", "version": "0.0.1", "description": "WebRTC codelab", "dependencies": { "node-static": "0.7.7", "socket.io": "1.2.0" } }
This is an app manifest that tells Node Package Manager (npm
)
what project dependencies to install.
To install dependencies, run the following from the command line terminal in your work directory:
npm install
You should see an installation log that ends something like this:
As you can see, npm
has installed the
dependencies defined in package.json.
You may get warnings, but if there are errors in red, ask for help!
Create a new file index.js at the top level of your work directory (not in the js directory) and add the following code:
'use strict';
var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');
var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
fileServer.serve(req, res);
}).listen(8080);
var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {
// convenience function to log server messages on the client
function log() {
var array = ['Message from server:'];
array.push.apply(array, arguments);
socket.emit('log', array);
}
socket.on('message', function(message) {
log('Client said: ', message);
// for a real app, would be room-only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function(room) {
log('Received request to create or join room ' + room);
var numClients = io.sockets.sockets.length;
log('Room ' + room + ' now has ' + numClients + ' client(s)');
if (numClients === 1) {
socket.join(room);
log('Client ID ' + socket.id + ' created room ' + room);
socket.emit('created', room, socket.id);
} else if (numClients === 2) {
log('Client ID ' + socket.id + ' joined room ' + room);
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room, socket.id);
io.sockets.in(room).emit('ready');
} else { // max two clients
socket.emit('full', room);
}
});
socket.on('ipaddr', function() {
var ifaces = os.networkInterfaces();
for (var dev in ifaces) {
ifaces[dev].forEach(function(details) {
if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
socket.emit('ipaddr', details.address);
}
});
}
});
});
From the command line terminal, run the following command in the work directory:
node index.js
From your browser, open localhost:8080.
Each time you open this URL, you will be prompted to enter a room name. To join the same room, choose the same room name each time, such as 'foo'.
Open a new tab page, and open localhost:8080 again. Choose the same room name.
Open localhost:8080 in a third tab or window. Choose the same room name again.
Check the console in each of the tabs: you should see the logging from the JavaScript above.
Bonus points
- What alternative messaging mechanisms might be possible? What problems might we encounter using 'pure' WebSocket?
- What issues might be involved with scaling this application? Can you develop a method for testing thousands or millions of simultaneous room requests?
- This app uses a JavaScript prompt to get a room name. Work out a way to get the room name from the URL. For example localhost:8080/foo would give the room name
foo
.
What you learned
In this step, you learned how to:
- Use npm to install project dependencies as specified in package.json
- Run a Node server to server static files.
- Set up a messaging service on Node using socket.io.
- Use that to create 'rooms' and exchange messages.
A complete version of this step is in the step-04 folder.
Find out more
- Socket.io chat-example repo
- WebRTC in the real world: STUN, TURN and signaling
- The term 'signaling' in WebRTC
Next up
Find out how to use signaling to enable two users to make a peer connection.