转载地址:https://blog.csdn.net/leytton/article/details/76831005
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连接.