html5 中最酷的特性之一是 WebSockets。WebSockets 允许我们与服务器通信,而不需要传统的 ajax 请求。
在本教程中,我们将学习很多关于 WebSockets 的知识。我们将构建一个通过 WebSockets 进行通信的客户端和服务器的实际示例。
什么是 WebSocket?
WebSockets 是一种通过一个 (TCP) 套接字进行双向通信的技术,是一种推送技术。
为什么我们需要 WebSockets?
当应用程序不支持长轮询时,WebSockets 被广泛使用。通过长轮询,服务器会不断发送可能包含也可能不包含所需数据的回复。需要此数据来保持连接的新鲜和活跃。当客户端收到数据时,它会检查并在需要时提出另一个请求。当然,长轮询有多种好处和用例。但是,长轮询并不是客户端-服务器通信的最佳和最奇特的技术。如果连接超时,则需要重新连接。此外,长轮询会导致资源利用率非常低。
这是需要推送技术的两个主要原因。正如它的名字所暗示的那样,只要有东西给客户端,服务器就会推送数据。这意味着客户不必定期提出请求。
让我们从网络服务器开始我们的演示。这是一个简单的演示,可帮助您开始使用整个技术。
1.构建 node.js 服务器
第 1 步:选择您的图书馆
对于 Node.js,您有十几个库可供选择来构建服务器。我最喜欢的是 ws,一个用于构建服务器的极其简单的库。该库允许我们创建服务器和客户端。多么酷啊?
当然,使用 ws 的先决条件是安装 Node.js。所以,不要忘记在您的系统中下载并安装 Node.js。
接下来,您需要安装库。好吧,这是一个非常简单的工作,您可以运行以下命令:
npm install ws
然后打开最喜欢的代码编辑器,并创建一个名为index.js的文件。
第 2 步:创建 WebSocket 服务器
首先,您需要导入ws模块。这个比较简单。您必须键入以下行,这将确保将 ws 导入到您的应用程序中。
接下来,您必须在端口上创建一个 Web 套接字服务器。客户端将通过此端口与服务器通信。在我们的例子中,端口号是 8081。
const wss = new WebSocket.Server({ port: 8081 })
那么,当客户端想要与服务器通信时应该怎么办呢?我们需要为此确定逻辑。ws 模块为以下每个状态更改提供了多个事件:
open
close
message
connection
upgrade
ping
此外,该模块还带有一些函数来触发和处理上述事件:
on
send
onerror
在我们的简单服务器中,只要客户端连接,我们就会发出connection事件。要发出其中一个事件,我们可以使用该on函数。
wss.on('connection', function connection(ws) {});
万一出现错误,onerror可以使用该功能。下面是一个简短的示例,说明如何使用这些功能。
ws.on("close", () => { /* handle the event */ }); ws.onerror = function (error) { /* handle the error */ }
我们的 WebSocket 服务器的基本框架,打开和关闭端口 8081 以供客户端连接,如下所示:
const WebSocket = require('ws') const wss = new WebSocket.Server({ port: 8081 }) wss.on('connection', function connection(ws) { ws.on("close", () => { console.log("Client disconnected"); }); ws.onerror = function () { console.log("Some Error occurred"); } });
第 3 步:接收消息
服务器只能对客户端执行这两种操作之一:发送消息或接收消息。首先,让我们看看如何从客户端接收消息。一旦建立了客户端和服务器连接,服务器就可以使用该message函数接收消息。
Websocket 通信总是与框架一起发生。这些是数据片段,从客户端传输到服务器,反之亦然。并且,数据片段可以采用以下格式:
文本 框: 这些包含原始文本形式的数据。
二进制 数据帧: 这些包含二进制数据。
乒乓帧:这些主要用于检查客户端和服务器之间是否建立了连接。浏览器通常负责响应这些消息。
连接关闭 帧:这些用于握手连接关闭。
当浏览器与服务器对话时(在我们的例子中发生),将使用文本或二进制帧。客户端的.send()功能倾向于将消息作为二进制或文本数据发送。这包括各种格式,例如ArrayBuffer, 和Blob。您无需配置任何内容即可以特定格式发送数据。只需将其发送出去并在服务器上解码即可。
同时,如果你想明确提及框架的类型,请使用.binaryType套接字的属性。
ws.binaryType = "arraybuffer"
如果要将缓冲区数据解码为字符串,可以使用以下函数。这里我们使用Buffer.from(), 然后.toString()将缓冲区转换为字符串。
ws.on("message", (msg) => { var buf = Buffer.from(msg); console.log(buf.toString()); });
第 4 步:向客户端发送消息
服务器的下一个功能是向客户端发送消息。为此,我们使用该功能。 ws.send()
现在我们已经确定并定义了服务器的基础知识,让我们构建应用程序,只要客户端与其连接,服务器就会向客户端发送消息。在下面的代码中,服务器'hello world' 每秒继续发送,直到客户端断开连接。
向客户端发送消息就是这么简单。
const interval = setInterval(() => { ws.send('hello world') }, 1000)
第 5 步:运行服务器
最后,您需要运行服务器。为此,您需要打开一个终端窗口,键入以下命令,并让服务器保持运行。不要忘记在文件夹中打开终端,其中存在在步骤 1 中创建的index.js 。
node index.js
并且,连接、断开连接、发送和接收消息的整个服务器代码如下所示:
const WebSocket = require('ws') const wss = new WebSocket.Server({ port: 8081 }) wss.on('connection', function connection(ws) { console.log('Client connected') const interval = setInterval(() => { ws.send('hello world') }, 1000) ws.on("close", () => { console.log("Client disconnected"); }); ws.onerror = function () { console.log("Some Error occurred"); } ws.on("message", (msg) => { var buf = Buffer.from(msg); console.log(buf.toString()); }); });
2.建立客户
现在,服务器已启动并运行,是时候构建客户端了。为此,使用以下文件创建另一个 Node 项目:
node_modules index.html index.js package.json
第 1 步:安装库
就像我们如何安装 ws 来构建我们的服务器一样,您也必须在客户端包中安装 ws。您的package.json应该具有以下依赖项:
{ "dependencies": { "ws": "^8.8.1" } }
第 2 步:连接到 Web 服务器
为了连接到 Web 服务器,我们必须初始化一个新的 WebSocket。而且,网络套接字需要连接到构建网络服务器时定义的端口。在我们的例子中,它将再次是 8081。
var hostURL = "ws://localhost:8081"; webSocket = new WebSocket(hostURL);
主机 URL 包含三个重要部分。
方案:ws
主机:本地主机
端口:8081
使用new WebSocket(url),连接会立即发生。在建立连接的过程中,客户端(又名浏览器)使用标头询问服务器是否支持 WebSockets。如果服务器响应为“是”,则建立连接,然后两人开始通话。使用的协议是 WebSocket 协议。在这里,我们根本不使用 HTTP 协议 !
在我们的客户端-服务器连接中,这里有一些请求标头。
GET ws://localhost:8081/ HTTP/1.1 Host: localhost:8081 Connection: Upgrade . . Upgrade: websocket . Sec-WebSocket-Version: 13 . . Sec-WebSocket-Key: cBtV+sKFkk3wqmFFr909Vg== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Connection: upgrade表示客户端需要切换协议。
Upgrade: websocket 提到请求的协议是“websocket”。
Sec-WebSocket-Key是浏览器生成的密钥。这是一个随机数,用于确保服务器支持 WebSocket 协议。它还可以防止各种代理缓存客户端和服务器之间进行的任何对话。
Sec-WebSocket-Version标识 WebSocket 协议的版本。最近的一个是13。
如果服务器同意建立连接,则响应为101。响应标头如下:
101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: abcd= Sec-WebSocket-Accept
有一个使用非常特殊的算法生成的密钥。当浏览器(又名客户端)注意到这个密钥时,它就知道服务器实际上支持 WebSocket 协议。此后,数据可以以帧的形式传输。
您无法模拟 WebSocket Handshakes。您不能使用fetch或XMLHttpRequest发出 HTTP 请求。为什么?因为 javascript 没有设置上面提到的 headers 的权限。
第 3 步:定义 WebSocket 事件
在我们定义我们的网络套接字事件之前,您需要更好地了解它们。在我们的客户端中,我们将使用三个不同的事件:
onOpen:套接字打开时触发的功能。
onMessage:从服务器接收到消息时触发的功能。
onClose:服务器关闭时触发的功能。
必须使用WebSocket对象调用上述事件。
webSocket.onopen = function(){} webSocket.onmessage = function(msg){} webSocket.onclose = function(){}
在我们的演示中,客户端将连接到服务器并在 HTML 页面上显示从服务器接收到的任何消息。同样,从连接到断开的任何状态变化都将打印到 HTML 页面。为此,我们将编写一个connect方法,该方法将相应地实现 Web Socket 事件。
function connect(){ try{ webSocket = new WebSocket(hostURL); messageDiv.innerHTML = "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; webSocket.onopen = function(){ messageDiv.innerHTML += "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; connectBtn.disabled = true; disconnectBtn.disabled = false; } webSocket.onmessage = function(msg){ messageDiv.innerHTML += "<p>Server response : " + msg.data + "</p>"; } webSocket.onclose = function(){ messageDiv.innerHTML += "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; connectBtn.disabled = false; disconnectBtn.disabled = true; } }catch(exception){ messageDiv.innerHTML += 'Exception happen, ' + exception; } }
你可以看到我们的 connect 函数有一个 try/catch 块。将所有服务器通信包含在 try/catch 块中是一种良好的编码习惯。如果出现问题,我们需要有一个后备策略。并且,try/catch 为我们提供了这个!它为客户端提供了一种让用户知道连接出现问题的方法。它也是调试整体流程的好地方。
在上述方法中,该onmessage函数的作用是在 HTML 页面上打印来自服务器的任何消息。
第 4 步:桥梁
connect 函数不会立即启动客户端-服务器连接。我们可以看到 thewebsocket被定义了,但是messageDiv, connectBtn, disconnectBtn, 和的定义hostUrl似乎来自其他地方。
我们将客户端代码分成两部分,init()和connect(). 函数负责init加载所有这些变量。而且,该init函数必须在页面加载时加载。init下面给出函数的定义。
function init(){ messageDiv = document.getElementById("message"); textInput = document.getElementById("text"); hostURL = "ws://localhost:8081"; websocketReadyStateArray = new Array('Connecting', 'Connected', 'Closing', 'Closed'); connectBtn = document.getElementById('connect'); disconnectBtn = document.getElementById('disconnect'); connectBtn.disabled = false; sendTextBtn.disabled = true; sendJSONObjectBtn.disabled = true; disconnectBtn.disabled = true; }
第 5 步:客户页面
客户端页面相当简单明了。我们将有以下内容:
adiv将加载来自服务器的消息的位置
两个buttons 连接,并断开与服务器的连接
这是用于构建此页面的 HTML 代码。需要在index.html中输入:
<!DOCTYPE html> <html> <head> <meta charset="ISO-8859-1"> <title>Html5 WebSockets Example</title> <script type="text/JavaScript" src="index.js" charset="utf-8"></script> <style> .block{ display:block; margin-top: 10px; } </style> </head> <body onload="init()"> <h3>Html5 WebSockets Example.</h3> <div id="message" class="block"></div> <button id="connect" onclick="connect()">Connect</button> <button id="disconnect" onclick="disconnect()">Disconnect</button> </body> </html>
建立连接后,客户端将从服务器收到“Hello World”。现在,页面将如下所示。
客户端index.js中的完整代码如下:
var webSocket; var messageDiv; var textInput; var hostURL; var websocketReadyStateArray; var connectBtn; var disconnectBtn; function init(){ messageDiv = document.getElementById("message"); textInput = document.getElementById("text"); hostURL = "ws://localhost:8081"; websocketReadyStateArray = new Array('Connecting', 'Connected', 'Closing', 'Closed'); connectBtn = document.getElementById('connect'); disconnectBtn = document.getElementById('disconnect'); connectBtn.disabled = false; sendTextBtn.disabled = true; sendJSONObjectBtn.disabled = true; disconnectBtn.disabled = true; } function connect(){ try{ webSocket = new WebSocket(hostURL); messageDiv.innerHTML = "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; webSocket.onopen = function(){ messageDiv.innerHTML += "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; connectBtn.disabled = true; disconnectBtn.disabled = false; } webSocket.onmessage = function(msg){ messageDiv.innerHTML += "<p>Server response : " + msg.data + "</p>"; } webSocket.onclose = function(){ messageDiv.innerHTML += "<p>Socket status:" + websocketReadyStateArray[webSocket.readyState] + "</p>"; connectBtn.disabled = false; disconnectBtn.disabled = true; } }catch(exception){ messageDiv.innerHTML += 'Exception happen, ' + exception; } } function selectAll(){ textInput.select(); } function disconnect(){ webSocket.close(); }
第 6 步:从客户端向服务器发送数据
直到,上面的这段代码,你将能够从服务器向客户端发送数据。为了将数据从客户端发送到服务器,您必须再执行几行代码。
我们将在我们的 HTML 页面中添加一个文本框,用户可以在其中输入数据。以及一个按钮,用于在单击时将文本框的内容发送到服务器。
<p class="block">Please input some text to Send : <input type="text" id="text" onfocus="selectAll()"/></p> <!-- ... --> <button id="sendMessage" onclick="sendMessage()">Send Message</button>
单击按钮时,将调用以下方法向服务器发送消息。由于使用了 Web 套接字的默认框架,因此消息将作为Buffer.
function sendMessage(){ webSocket.send(textInput.value) }
单击Send Message后,服务器的控制台中会显示以下内容,如下所示:
第 7 步:运行客户端
要运行客户端,您不必做太多事情。您需要在您喜欢的浏览器中打开index.html,然后单击“连接”与服务器建立连接。
而已!
结论
使用 HTML 和 javascript (NodeJS) 的 WebSockets 教程到此结束。WebSockets 非常令人高兴,并且在过去几年中发生了翻天覆地的变化。WS 只是众多可供选择的 Web 套接字库之一。您必须密切关注 W3C WebSocket api,以了解有关此 PUSH 技术的最新变化的所有信息。
WebSocket 是一种建立浏览器-服务器连接的持久方法。这些没有跨源限制,并且在所有现代浏览器中都受支持。API 很简单,有 和 之类的.send方法.close。
- 什么是 WebSocket?
- 为什么我们需要 WebSockets?
- 第 1 步:选择您的图书馆
- 第 2 步:创建 WebSocket 服务器
- 第 3 步:接收消息
- 第 4 步:向客户端发送消息
- 第 5 步:运行服务器
- 第 1 步:安装库
- 第 2 步:连接到 Web 服务器
- 第 3 步:定义 WebSocket 事件
- 第 4 步:桥梁
- 第 5 步:客户页面
- 第 6 步:从客户端向服务器发送数据
- 第 7 步:运行客户端
发表评论