跳转至

搭建信令服务交换消息(五)

你会学到什么

在这一步中,您将了解如何:

  • 使用npm来安装package.json中指定的项目依赖关系
  • 运行Node.js服务器并使用node-static来提供静态文件。
  • 使用http://Socket.IO在Node.js上设置消息服务。
  • 用它来创建“房间”并交换信息。

此步骤的完整版本位于step-04文件夹中。

一些概念

为了建立和维护WebRTC呼叫,WebRTC客户(对等)需要交换元数据:

Candidate(网络)信息。

Offeranswer 支持媒体信息的消息,如分辨率和编解码器。

换句话说,在音频,视频或数据的点对点流式传输可能发生之前,需要交换元数据。 这个过程被称为信令。

在前面的步骤中,发送者和接收者的 RTCPeerConnection 对象在同一个页面上,所以“信号”就是在对象之间传递元数据。

在真实世界的应用程序中,发送者和接收者RTCPeerConnections在不同设备上的网页中运行,您需要一种方式让他们交流元数据。

为此,您使用信令服务器:可以在WebRTC客户端(对等端)之间传递消息的服务器。 实际的消息是纯文本:字符串格式的JavaScript对象。

先决条件:安装Node.js

为了运行这个代码(文件夹step-04到step-06),你将需要使用Node.js在本地上运行一个服务器。

您可以从此链接下载并安装Node.js,也可以通过首选的包管理器进行安装。

安装完成后,您将能够导入(运行npm install)所需的依赖关系,并在本地主机运行一个小型服务器来执行代码(运行节点index.js)。 这些命令稍后将会需要。

关于应用程序

WebRTC使用客户端JavaScript API,但是对于真实世界的使用还需要一个信令(消息)服务器,以及STUN和TURN服务器。 你可以在这里找到更多。

在这一步中,您将构建一个简单的 Node.js 信令服务器,使用Socket.IO Node.js模块和JavaScript库进行消息传递。 使用Node.js和Socket.IO的经验将是有用的,但不是关键; 消息传递组件非常简单。

选择正确的信令服务器
这个代码使用Socket.IO作为信号服务器。
http://Socket.IO的设计使构建服务、交换消息变得简单,http://Socket.IO适用于WebRTC信令,因为它内置了“房间”的概念。
对于生产服务来说,可能有更好的选择。 请参阅如何为您的下一个WebRTC项目选择信号协议

在这个例子中,服务器(Node.js应用程序)在index.js中实现,客户端(web应用程序)在index.html中实现。

本步骤中的Node.js应用程序有两个任务。

首先,它作为一个消息中继:

socket.on('message', function (message) {
    log('Got message: ', message);
    socket.broadcast.emit('message', message);
});

其次,它管理WebRTC视频聊天“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);
}

我们简单的WebRTC应用程序将允许最多两个对等体共享一个房间。

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>

在此步骤中,您将看不到页面上的任何内容:所有日志记录均已完成到浏览器控制台。 (要在Chrome中查看控制台,请按Ctrl-Shift-J或Command-Option-J(如果您是Mac上)。

将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);
});

安装 Socket.IO 以在 Node.js 上运行

在HTML文件中,您可能已经看到正在使用的http://Socket.IO文件:

<script src="/socket.io/socket.io.js"></script>

在工作目录的根目录下创建一个名为package.json的文件,其内容如下:

{
    "name": "webrtc-codelab",
    "version": "0.0.1",
    "description": "WebRTC codelab",
    "dependencies": {
    "node-static": "^0.7.10",
    "socket.io": "^1.2.0"
    }
}

这是一个应用程序清单,它告诉节点包管理器(npm)安装哪些项目依赖项。

要安装依赖关系(例如/http://socket.io/socket.io.js),请在您的工作目录中运行命令(命令行终端运行):

npm install

您应该看到一个安装日志,结果如下所示:

如你所见,npm安装了package.json中定义的依赖关系。

在工作目录的顶层(不在js目录中)创建一个新的文件index.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);
        }
        });
    }
    });

});

从工作目录运行命令行终端,输入以下命令:

node index.js

在浏览器中打开localhost:8080。

每次打开此URL时,系统都会提示您输入房间名称。 要加入同一房间,请每次选择相同的房间名称,例如“foo”。

打开一个新的标签页,并再次打开localhost:8080。 选择相同的房间名称。

在另外一个选项卡或窗口中打开localhost:8080。 再次选择相同的房间名称。

检查每个选项卡中的控制台:您应该从上面的JavaScript中看到日志记录。

知识扩展

  • 还有哪些可能的消息传递机制? 使用“纯”的WebSocket可能遇到什么问题?
  • 扩展这个应用程序可能涉及哪些问题? 你能开发一种方法来测试数千或数百万个同时的房间请求吗?
  • 这个应用程序使用JavaScript提示来获取房间名称。 找出从URL获取房间名称的方法。 例如localhost:8080/foo会给出房间名称foo。

你学到了什么

在这一步中,您学习了如何:

  • 使用npm来安装package.json中指定的项目依赖关系
  • 运行一个Node.js服务器。
  • 使用http://socket.io在Node.js上设置消息服务。
  • 用它来创建“房间”并交换信息。

此步骤的完整版本位于step-04文件夹中。

了解更多

下一步

了解如何使用信令将两个用户建立对等连接。