照片来自Unsplash上的Cytonn Photography
以下是本系列文章的链接:
1.来自网络摄像头和麦克风的数据流(访问用户设备以及数据流,并在浏览器上显示视频(带音频))
2.通过 WebSocket 建立连接(在两个用户之间通过 WebSocket 建立 P2P 连接)
3.建立 WebRTC 连接( 建立 WebRTC 连接,真正开启视频聊天)
4.查找联系人(调整 WebSocket 服务器和客户端代码,使用户只有输入相同代码才会建立彼此联系)
5.与 WebRTC 共享您的屏幕(将 RTCPeerConnection 对象的视频轨道替换为显示媒体流的视频轨道,使用户之间共享屏幕)
我们在上一篇文章中 知道了如何从浏览器访问网络摄像头和麦克风流,现在要开始在两个用户之间建立 P2P 连接。
本地浏览器和远程用户(对等方)之间的 WebRTC 连接将由 JavaScript 接口RTCPeerConnection 表示。但你必须先协调这个连接,在对等点之间交换消息以找到彼此位置,控制通信然后终止它,这就是信令过程。信令过程不是 WebRTC 规范的一部分,你可以自由使用任何想要建立和控制连接的消息传递协议。从技术层面上讲,你可以在每个帖子中传递这些消息,但常见的解决方案是使用 WebSocket 协议。
在本文中,我们将允许两个用户通过 WebSocket 进行通信。我们将使用 Node 服务器作示范,其中对等方可以创建连接、互相打招呼并关闭连接。
WebSocket
WebSocket 是一种通信协议,类似于 HTTP。与 HTTP 一样,WebSocket 支持客户端(浏览器)和服务器之间的通信。
当通过HTTP进行 通信时,服务器只能对客户端的请求做出反应。它不记得以前请求的内容,HTTP 是无状态的。另一方面,WebSocket 允许你在客户端和服务器之间创建一个通道。一旦这个通道打开,直到它关闭,通信都可以双向进行:服务器可以随时发送数据,客户端也可以。
WebSocket 实际上的设计宗旨是通过为HTTP 工作,因此我们可以使用普通的 Web 服务器来创建它。我们将在客户端和 Node 服务器之间实现 WebSocket 通信。
设置Node项目
为此,我们将使用 Node 服务器和一个能实现 WebSocket 的库:WebSocket-Node。
如果你还没有安装,你应该先安装Node.js。创建要在其中放置 WebSocket 项目的文件夹(我将其命名为web-socket )。然后进入该文件夹初始化你的项目:
npm init
Create a file index.js and install the WebSocket-Node library using npm:
创建文件 index.js 并使用 npm安装WebSocket-Node库:
npm install websocket --save
按照库的文档,我们首先需要定义一个 HTTP 服务器。我们将侦听端口 1337。然后我们在它的顶部创建 WebSocket 服务器。
const http = require('http');
const server = require('websocket').server;
const httpServer = http.createServer(() => { });
httpServer.listen(1337, () => {
console.log('Server listening at port 1337');
});
const wsServer = new server({
httpServer,
});
我们想进行一些简单操作来理解 WebSocket 的工作原理。每个人都可以通过我们的服务器连接和发送消息。当用户发送消息时,所有其他与之连接的用户都会收到它。
let clients = [];
wsServer.on('request', request => {
const connection = request.accept();
const id = Math.floor(Math.random() * 100);
clients.forEach(client => client.connection.send(JSON.stringify({
client: id,
text: 'I am now connected',
})));
clients.push({ connection, id });
connection.on('message', message => {
clients
.filter(client => client.id !== id)
.forEach(client => client.connection.send(JSON.stringify({
client: id,
text: message.utf8Data,
})));
});
connection.on('close', () => {
clients = clients.filter(client => client.id !== id);
clients.forEach(client => client.connection.send(JSON.stringify({
client: id,
text: 'I disconnected',
})));
});
});
我们需要跟踪连接的用户,我们在客户端 数组中这样做。当用户请求连接时,我们先点击接受,然后通知所有其他已连接用户。接着,我们生成一个随机 id,然后将具有此 id 的新连接添加到数组中。
当用户发送消息时,会发出事件消息 。除了发送消息的用户之外,每个连接的用户都会收到一些数据,其中包含消息的文本和发送消息的用户的索引。
最后,当用户断开连接时,他会被移出客户端 列表,并且其余用户都会收到有关它的通知。
现在让我们通过创建一个简单的用户界面来检查这是否有效。
客户端
我们不会在客户端中创建任何复杂的东西,我们只想确保通信正常运行。我们将显示三个按钮:
- 一键连接
- 一键发送“你好!” 信息
- 一键断开
当用户未连接时,仅启用第一个按钮,否则仅启用最后两个按钮。
在按钮下方,我们显示了一些将要打印消息的区域(在代码中称为控制台 )。
你可以为客户端代码创建一个新文件夹(我将其命名为我的客户端 )。再操作一遍,我们可以让事情变得更简单,你只需要index.html 、index.js 和styles.css 文件。HTML 和 CSS 就非常简单:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>VideoChat</title>
<script src="index.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<button id="start">Connect to WebSocket</button>
<button id="say-hello" disabled>Say Hello</button>
<button id="close" disabled>Leave</button>
<div id="console"></div>
</body>
</html>
button {
display: block;
margin: auto;
margin-bottom: 10px;
padding: 10px;
font-size: 16px;
background-color: seagreen;
border: 1px solid seagreen;
color: white;
border-radius: 3px;
font-weight: bold;
cursor: pointer;
}
button:disabled {
cursor: not-allowed;
background-color: grey;
border: 1px solid grey;
}
#console {
width: 400px;
height: 400px;
border: 1px solid black;
border-radius: 3px;
margin: auto;
margin-top: 30px;
}
你可以在下面找到整个index.js 文件,但为了使其更易于理解,我们首先将重点放在摘录上。
我们需要定义点击按钮时会发生的反应。单击第一个按钮时,我们要初始化连接。当第二个按钮被点击时,我们想通过连接发送消息“你好!” 。单击最后一个按钮应关闭连接。connection 是一个全局变量,在setupWebSocketConnection 函数中被初始化。
document.addEventListener('click', async event => {
if (event.target.id === 'start') {
setupWebSocketConnection();
} else if (event.target.id === 'say-hello') {
connection.send('Hello!');
} else if (event.target.id === 'close') {
closeConnection();
}
});
最有趣的部分当然是如何建立连接。
const setupWebSocketConnection = () => {
connection = new WebSocket('ws://127.0.0.1:1337');
connection.onopen = () => {
addMessageToConsole('You are now connected!');
enableAndDisableButtons(true);
};
connection.onerror = error => {
console.log(`An error occured: ${error}`)
};
connection.onmessage = message => {
const data = JSON.parse(message.data);
addMessageToConsole(`Client${data.client} says: ${data.text}`)
};
}
我们只需创建一个WebSocket 类的实例,将 url 作为参数传递。然后我们定义事件处理程序。当连接打开时,我们向控制台添加一条消息并正确设置按钮的禁用属性。当收到消息时,我们将其显示在控制台中。
连接打开后,通过它发送消息就简单多了:
connection.send('Hello!');
以上你可以在事件侦听器函数中看到。关闭连接也很简单,正如在closeConnection 函数中看到的:
const closeConnection = () => {
connection.close();
addMessageToConsole('You disconnected!');
enableAndDisableButtons(false);
}
和所说的一样,这里是完整的index.js 文件:
(function () {
"use strict";
let connection;
const enableAndDisableButtons = (connected) => {
document.getElementById('start').disabled = connected;
document.getElementById('say-hello').disabled = !connected;
document.getElementById('close').disabled = !connected;
}
const setupWebSocketConnection = () => {
connection = new WebSocket('ws://127.0.0.1:1337');
connection.onopen = () => {
addMessageToConsole('You are now connected!');
enableAndDisableButtons(true);
};
connection.onerror = error => {
console.log(`An error occured: ${error}`)
};
connection.onmessage = message => {
const data = JSON.parse(message.data);
addMessageToConsole(`Client${data.client} says: ${data.text}`)
};
}
const closeConnection = () => {
connection.close();
addMessageToConsole('You disconnected!');
enableAndDisableButtons(false);
}
const addMessageToConsole = message => {
const messageDiv = document.createElement('div');
messageDiv.textContent = message;
document.getElementById('console').appendChild(messageDiv);
}
document.addEventListener('click', async event => {
if (event.target.id === 'start') {
setupWebSocketConnection();
} else if (event.target.id === 'say-hello') {
connection.send('Hello!');
} else if (event.target.id === 'close') {
closeConnection();
}
});
})();
测试
现在启动服务器并在两个客户端之间尝试我们的消息传递系统。要运行服务器,需转到web-socket 文件夹并运行:
node index.js
你应该在终端中看到“服务器在端口 1337 上侦听”。
要测试两个客户端是否可以通过服务器进行通信,需在两个选项卡或两个浏览器窗口中打开index.html 。
现在随意单击按钮,你可以看到客户端之间正在交换消息:
通过 WebSocket 的通信正在工作。
我们设置了一个 WebSocket 服务器以允许两个客户端交换消息。换个思路,我们现在可以使用这个通道来交换必要的消息创建和控制 WebRTC 连接。这就是我们在下一篇文章中要做的内容。
原文作者 Heloise Parein
原文链接 https://levelup.gitconnected.com/set-up-a-connection-over-websocket-videochat-with-javascript-step-2-f78c307c4fd3