Node 中的 Sockets.IO 介绍
套接字.IO :
早些时候,网站过去常常在每次请求资源时重新加载。这引入了不必要的延迟,增加了平均等待时间。通常,用户必须等待几分钟才能获取特定页面或文件。另一方面,实时应用程序(即时通讯、在线游戏、推送通知等)是那些在给定时间段内运行的应用程序,以便向用户呈现资源的即时和最新副本。这些应用程序的延迟尽可能低,以提供流畅和一致的用户体验。 Socket.IO 就是这样一种 JavaScript 库,程序员可以使用它来开发实时“Web 应用程序”。
为什么 Sockets.IO :
当今互联网上的大多数应用程序都是基于客户端-服务器架构。客户端是从服务器请求某些东西的人。服务器根据请求以适当的结果进行响应。由于它们执行的任务的性质,这两个实体彼此完全不同。浏览器是客户端应用程序的完美示例。浏览器上的客户端通常通过 HTTP 请求和响应与服务器通信。这种通信的问题在于,可以一次发送请求或响应。为便于理解,可将其视为半双工链路。此外,HTTP 标头包含大量冗余信息,一旦在客户端和服务器之间建立连接,这些信息就毫无用处。另一方面,套接字在网络堆栈的传输层上工作。没有太多的冗余字段,从而提高了网络信息传输的效率。
Socket.IO 基于相同的概念工作,并支持 Web 客户端和服务器之间的双向通信。为了分别有效地处理它们,它由两部分组成;
- 在浏览器上运行的 JavaScript 客户端库。
- 一个 Node.js 服务器
Socket.IO 依赖于 Engine.IO,它是基于传输的跨浏览器/跨设备双向通信层的实现。它为 Socket.IO 带来了以下特性;
- 可靠性:即使存在代理、负载平衡器、个人防火墙和防病毒软件,它也可以建立连接。
- 自动重新连接支持:除非在代码中明确提及,否则客户端库将永远尝试重新连接,直到服务器再次可用。
- 断开连接检测:它允许服务器和客户端知道对方何时不再响应。
- 多路复用支持:它允许在同一个底层连接上有多个通信通道。
- 二进制流支持:它还允许发出任何可序列化的二进制数据,如 ArrayBuffer、Blob 等。
安装:
- 安装 Sockets.IO 所需
- 节点已安装
- 安装了npm(节点包管理器)
如前所述,项目中包含两个不同的库。
- 服务器:
要将其安装在 Node.js 项目中,请运行以下命令,$ npm install --save socket.io
- JavaScript 客户端:
默认情况下,服务器在/socket.io/socket.io.js处公开客户端的独立构建。否则,也可以从任何 CDN 提供商处提供服务。要从 Node.js 使用它,请通过以下命令安装它,
$ npm install --save socket.io-client
例子:
这个例子是关于在 Socket.IO 中实现一个基本的 Upvote 按钮。它将显示实时服务器和客户端通信。首先,转到所需的项目目录并使用npm init命令或手动创建package.json文件对其进行初始化。
{
“name”: “upvote-example”,
“version”: “0.1”,
“description”: “the very first socket.io app”,
“main”: “index.js”,
“dependencies”: {}
}
现在使用以下命令安装 express js,
$ npm install --save express@4.15.2
安装后,创建将设置应用程序的index.js文件。
var app = require( ‘express’ )();
var http = require( ‘http’ ).createServer( app );
const PORT = 3000;
app.get( ‘/’, function( req, res ) {
res.send( ‘
Hello World
‘ );
});
http.listen( PORT, function() {
console.log( ‘listening on *:’ + PORT );
});
这段代码的作用是为 Express 创建一个函数处理程序,然后将其提供给 HTTP 服务器。当请求/页面时,此处理程序向客户端响应“Hello World”。最后,HTTP 服务器开始监听 3000 端口。
运行它看起来像这样,
服务 HTML:
以前,只发送一个 HTML 行作为对 GET 请求的响应。这一次,使用sendFile方法附加一个 HTML 文件。
app.get( ‘/’, function( req, res ) {
res.sendFile( __dirname + ‘/public/index.html’ );
});
现在创建index.html文件并粘贴以下代码。
SocketIO Upvote
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam sed turpis sit amet tellus convallis tincidunt quis ut massa. Phasellus maximus
orci quis mauris tincidunt, ut tempor turpis tincidunt. Curabitur vestibulum nunc consequat
venenatis ultrices. Aliquam eget congue risus, in imperdiet urna. Vestibulum varius velit
risus, non luctus arcu placerat vel. In hac habitasse platea dictumst. Pellentesque vitae
justo volutpat, euismod ligula quis, posuere nibh.
0 Upvotes
重新启动项目并刷新页面,它应该看起来像这样,
集成Socket.IO:
要安装服务器端模块,请运行以下命令,
$ npm install --save socket.io
现在对index.js进行如下更改,
var app = require( ‘express’ )();
var http = require( ‘http’ ).createServer( app );
var io = require( ‘socket.io’ )( http );
const PORT = 3000;
app.get( ‘/’, function( req, res ) {
res.sendFile( __dirname + ‘/public/index.html’ );
});
http.listen( PORT, function() {
console.log( ‘listening on *:’ + PORT );
});
io.on( ‘connection’, function( socket ) {
console.log( “a user has connected!” );
});
其他更改初始化 Socket.IO 处理程序。当它发出一个“连接”信号时,一个记录操作被附加到这个处理程序。
在客户端,在关闭标记之前,只需要以下代码片段即可。这公开了一个特定客户端使用的io全局。
从控制台再次重新启动项目并尝试在多个选项卡和浏览器上打开本地主机。它们中的每一个都将充当唯一的客户端连接。每次在客户端和服务器之间建立连接时都会打印日志消息。
当客户端关闭或刷新选项卡时,每个套接字还会触发一个特殊的断开连接事件:
io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );
socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});
});
发射事件:
Socket.IO 背后的主要思想是可以发送和接收任何选择的事件,无论是否有任何数据。任何可以编码为 JSON 的对象都可以,并且也支持二进制数据。
假设当用户单击 upvote 按钮时,会发出一个名为upvote-event 的事件。所以在index.html文件中,插入以下脚本。
在index.js 中,以下代码片段用于记录事件数据。
io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );
socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});
socket.on( ‘upvote-event’, function( upvote_flag ) {
console.log( ‘upvote: ‘ + upvote_flag );
});
});
结果应该是这样的,
广播:
下一个目标是从服务器向其他用户发出事件。这一次,基于点击的投票计数将被广播到每个连接到服务器的客户端。我们将此事件称为update-upvotes 。为了计算赞成票的数量,让我们创建一个变量upvote-count 。像这样更新index.js ,
var upvote_count = 0;
io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );
socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});
socket.on( ‘upvote-event’, function( upvote_flag ) {
upvote_count += upvote_flag ? 1: -1;
var f_str = upvote_count + ( upvote_count == 1 ? ‘ upvote’: ‘ upvotes’);
io.emit( ‘update-upvotes’, f_str );
});
});
在这里, upvote_count初始化为零(0)并根据upvote_flag的值进行更新。然后将更新的值发送到所有客户端,包括发生“更新事件”的客户端。
在客户端,像这样更新index.html ,
它将使用投票计数的当前值更新 DOM 元素。结果看起来像这样,
要使这个示例在实际开发中健壮和可用,需要考虑很多事情。应该考虑这样一个事实,当多个用户同时点击upvote按钮时,这个例子会遇到竞争条件的问题。应该使用适当的锁定机制使其在现实世界的应用程序中工作。
得到这个例子:
在此处在 Github 上查找此示例的完整代码。
Git 仓库:
https://github.com/CherryGot/SocketIO-Upvote.git