五、实时双向通信

我们一直在使用 COMET 技术来实现网络浏览器和网络服务器之间的双向通信。长轮询是实现 web 浏览器和 web 服务器之间双向通信的最流行的技术,因为它在不影响用户体验和不需要任何额外的服务器配置的情况下工作,并且它可以在所有支持 AJAX 的 web 浏览器上工作。长轮询可以很容易地在任何现有的 HTTP 服务器上实现。但是长轮询和其他 comet 技术的问题是,由于 HTTP 开销,它们都不适合构建实时应用。这意味着每次发出 HTTP 请求时,都会有一堆头和 cookie 数据被传输到服务器,这反过来又会增加延迟,因此不适合创建需要实时双向通信的应用,如多人游戏、聊天应用、社交网络和实时评分网站。因此,引入了名为网络套接字的新协议,该协议旨在实现网络浏览器和网络套接字服务器之间的实时双向通信。

在本章中,我们将介绍以下内容:

  • 网络套接字概述
  • 网络套接字和 HTTP 的关系
  • 网络套接字与代理服务器和防火墙的交互
  • 使用套接字实现网络套接字。超正析象管(Image Orthicon)
  • 插座。深度 IO 应用编程接口
  • 许多其他重要的事情与网络套接字和套接字有关。超正析象管(Image Orthicon)

介绍 WebSocket

WebSocket 是一种应用层协议,旨在促进 web 浏览器和 WebSocket 服务器之间的双向(无论是客户端还是服务器,只要有消息,就可以向对方发送消息)和全双工通信(客户端和服务器都可以同时向对方发送消息)。

WebSocket 是一个二进制协议;因此,它比 HTTP 协议更快,HTTP 协议是一种基于文本的协议。

由于其实时性和全双工特性,WebSocket 已经获得了普及,并且已经被许多网站使用。由于 comet 技术造成的开销,它不适合实时双向消息传输,也不可能使用 comet 在 web 浏览器和 web 服务器之间建立全双工通信系统。也就是说,comet 技术让我们只能实现半双工通信系统(在给定时间只有客户端或服务器可以向对方发送消息)。

网络套接字旨在促进网络浏览器和网络套接字服务器之间的双向通信,但它可以被任何客户端使用。在这一章中,我们将只关注如何在网络浏览器中实现它。

什么是 WebSocket API?

网络浏览器提供了一个应用编程接口,用于创建和管理与网络套接字服务器的网络套接字连接,以及在该连接上发送和接收数据。我们不会使用这个应用编程接口来实现网络套接字;相反,我们将使用套接字。IO 库。

【WebSocket 与 HTTP 的关系

WebSocket 和 HTTP 之间唯一的关系是 web 浏览器和 WebSocket 服务器之间的 WebSocket 握手是使用 HTTP 完成的。因此,网络套接字服务器也是一个 HTTP 服务器。握手成功后,同样的 TCP 连接用于 WebSocket 通信,即通信切换为双向二进制协议,不符合 HTTP 协议。网络套接字的默认端口号是 80,与 HTTP 相同。

为什么默认的 WebSocket 端口是 80?

将 HTTP 和 WebSocket 如此紧密地集成在一起,并使 WebSocket 共享 HTTP 端口的主要原因是为了防止防火墙阻止非 web 内容。

虽然如果您在网络浏览器环境之外使用网络套接字,您可以实现自己的网络套接字握手机制,但官方的网络套接字文档仅说明了 HTTP 握手机制,因为网络套接字旨在实现网络浏览器和网络套接字服务器之间的双向通信。

您可以将网络套接字服务器集成到为您的 HTML 页面提供服务的主网络服务器中,也可以使用单独的网络服务器进行网络套接字通信。

通过网络套接字连接发送和接收数据

数据作为消息通过网络套接字连接传输,每个由一个或多个包含您正在发送的数据(称为有效负载)的帧组成。为了确保消息在到达另一方时能够被正确地重构,每个帧都带有关于有效载荷的 4-12 字节的数据作为前缀。使用这种基于帧的消息传递系统有助于减少传输的非有效负载数据量,从而显著降低延迟,因此有可能构建实时组件。

我们不会深入讨论网络套接字握手、数据帧以及发送和接收数据的确切数据格式和其他细节,因为只有当您计划创建自己的网络套接字服务器时,这才是必需的。我们将使用套接字。IO JavaScript 库在我们的应用中实现 WebSocket,它照顾到了 WebSocket 的所有内部细节,并提供了一个易于使用的 API。

网络套接字方案

WebSocket 协议规范引入了两个新的 URL 方案,分别叫做 wswss

ws代表未加密连接,而wss代表加密连接。加密连接使用 TLS 来加密消息。

所以,在使用 HTTP 进行 WebSocket 握手请求时,我们需要分别使用ws或者wss来代替http或者https

为什么是wswss而不是httphttps

你一定想知道引入一个新的方案而不是仅仅使用http有什么意义。这背后的原因是,网络套接字也可以在网络浏览器环境之外使用,握手可以通过非 HTTP 服务器协商。因此,当不使用 HTTP 进行握手时,需要不同的方案。

网络套接字与代理服务器、负载平衡器和防火墙的交互

网络套接字协议本身不知道代理服务器。当网络套接字连接在代理服务器后面建立时,网络套接字连接可能会失败或正常工作,这取决于代理服务器是透明的还是显式的,以及我们是否建立了安全或不安全的连接。

如果浏览器被配置为使用显式代理服务器,那么在建立网络套接字连接时,它将首先向该代理服务器发出HTTP CONNECT方法。CONNECT方法用于告诉代理与另一台主机建立连接,并简单地回复内容,而不尝试解析或缓存内容。无论连接是加密的还是未加密的,浏览器都会发出HTTP CONNECT方法。

如果我们使用的是透明的代理服务器(即网络浏览器不知道的代理服务器),并且连接是加密的,那么浏览器不会发出HTTP CONNECT方法,因为它不知道代理服务器。但是由于连接是加密的,代理服务器很可能会让所有加密的数据通过,因此不会对网络套接字连接造成问题。

如果我们使用的是透明的代理服务器,并且连接未加密,那么浏览器不会发出HTTP CONNECT方法,因为它不知道代理服务器。但是由于连接是未加密的,代理服务器可能会尝试缓存、解析或阻止数据,从而导致网络套接字连接出现问题。在这种情况下,应该升级或显式配置代理服务器以支持网络套接字连接。

网络套接字协议本身并不知道负载平衡器。如果您使用的是 TCP 负载平衡器,它不太可能对网络套接字连接造成任何问题。但是如果使用的是 HTTP 负载均衡器,很可能会出现问题;因此,它需要升级或显式配置以处理 WebSocket 连接。

WebSocket 协议本身并不知道防火墙。防火墙不太可能对网络套接字连接造成任何问题。

【WebSocket 的同源策略

浏览器作为以及 WebSocket 实例可以执行跨域通信,也就是说,它们不受任何同源策略的限制。

当发出握手的 HTTP 请求时,浏览器发送一个分配给网页源的Origin头。

如果一个网络套接字服务器想要将通信限制在一个特定的域,它可以读取握手 HTTP 请求的Origin HTTP 头,并相应地阻止或允许握手。

插座介绍。超正析象管(Image Orthicon)

插座。IO 是客户端 JavaScript 库和 Node.js 库的组合,用于集成浏览器和 Node.js 后端之间的双向通信。

插座。IO 客户端库用于创建套接字。输入输出客户端,而套接字。IO Node.js 库用于创建一个 Socket。IO 服务器。Socker。IO 客户端和服务器可以双向通信。插座。IO 主要使用 WebSocket 实现双向通信。

使用套接字的主要原因。IO 客户端库而不是使用 WebSocket API 的原因是,WebSocket 在编写时是一个相对较新的协议,并非所有浏览器都支持该 API。如果插座。IO 看到浏览器不支持 WebSocket,那么就会跳转到其他机制之一,比如 Flash sockets、长轮询、多部分流、iframes 或者 JSONP 轮询,实现浏览器和服务器之间的双向通信。因此,我们可以说 Socket。IO 保证可以在每个浏览器上工作。插座。IO 后端库提供了创建名称空间和房间、广播消息等的 API,在某些情况下非常有用。因此,Socket。IO 是实现浏览器和 Node.js 服务器之间双向通信的最佳方式。

设置您的项目

在之前,我们开始学习插座。IO API,我们先来设置我们的项目目录和文件。创建一个名为SocketIO-Example的目录。在目录中,创建名为package.jsonapp.jssocket.js的文件和名为public的目录。在public目录中,创建两个目录,htmljs。在html目录中,创建一个名为index.html的文件。最后,在js 目录下,下载并放置 Socket。IO 库来自https://cdn.socket.io/socket.io-1.3.7.js。在撰写本文时,最新版本的 Socket。IO 为 1 . 3 . 7;因此,我们将使用该版本。

app.js文件内部,我们将为 web 服务器编写代码,在socket.js文件内部,我们将为 Socket 编写代码。IO 服务器。现在,我们将运行两个不同的服务器,也就是说,一个单独的 web 服务器为网站服务,另一个服务器用于双向通信。在下一章中,我们将学习如何集成 Socket。带快速服务器的输入输出服务器。

package.json文件中,放置以下代码:

{
  "name": "SocketIO-Example",
  "dependencies": {
    "express": "4.13.3",
    "socket.io": "1.3.7"
  }
}

现在,在SocketIO-Example目录中运行npm install命令,以便下载并安装 Express 和 Socket。IO Node.js 库。

现在,在index.html文件中,放置以下 HTML 代码:

<!doctype html>
<html>
  <head>
    <title>SocketIO-Example</title>
  </head>
  <body>
    <script src="js/socket.io-1.3.7.js"></script>
    <script>
      //place JavaScript code here
    </script>
  </body>
</html>

在第二个<script>标签中,您将放置插座。IO 客户端代码。

现在,将此代码放在app.js文件中,以服务于index.html文件:

var express = require("express");
var app = express();

app.use(express.static(__dirname + "/public"));

app.get("/", function(httpRequest, httpResponse, next){
  httpResponse.sendFile(__dirname + "/public/html/index.html");
})

app.listen(8080);

这里,我们正在监听端口8080。运行app.js文件,访问http://localhost:8080/网址,加载index.html页面。

我们已经完成了文件和目录的设置。现在,让我们了解一下套接字。IO 客户端和服务器端 API。

潜入插座。输入输出应用编程接口

我们先来看看对 Socket 的概述。IO API。之后,我们将逐一进入高级功能。

让我们首先构建一个套接字。IO 服务器。下面是创建套接字的代码。IO 服务器实例并侦听新的套接字。IO 客户端握手请求。将其放入socket.js文件中:

var Server = require("socket.io");
var io = new Server({path: "/websocket"});
io.listen(3000);

下面是代码的工作原理:

  1. 首先,我们导入套接字。IO Node.js 库。
  2. 然后,我们创建一个新的套接字实例。IO 服务器使用Server构造函数。
  3. 然后,在创建新实例时,我们将套接字传递到的 HTTP 路径。IO 客户端将发出握手请求。如果不经过路径,默认为/ socket.io
  4. 最后,我们收听端口3000

我创建了一个单一的套接字。代码中的 IO 服务器,但我们可以自由创建多个服务器监听不同的端口。

现在,插座。输入输出客户端可以发送握手请求,而套接字。IO 服务器可以建立一个 Socket。与其客户端的 IO 连接。让我们写一些代码在套接字上做一些事情。套接字后的输入输出服务器。IO 连接已经建立。将该代码放入socket.js文件:

io.on("connection", function(socket){

  socket.send("Hi, from server");

  socket.on("message", function(message){
    console.log(message);
  });

  socket.on("disconnect", function(){ 
    console.log("User Disconnected");
  });

  socket.emit("custom-event", "parameter1", "parameter2");

  socket.on("custom-event", function (parameter1, parameter2) {
    console.log(parameter1, parameter2);
  });
});

让我们看看这个代码是如何工作的,以及send()on()emit()方法是做什么的:

  • io对象的on()方法用于将事件处理程序附加到套接字上触发的事件。IO 服务器本身。
  • 我们首先为connection事件附加一个事件处理程序。只要一个插座。IO 连接已经建立,connection事件被触发。事件处理程序只有一个参数,它是一个表示套接字的对象。IO 客户端。这里,我们已经命名了参数socket
  • socket对象的on()方法用于将事件处理程序附加到套接字发出的事件上。IO 客户端到服务器。
  • socket对象的send()方法用于向 Socket 发送消息。IO 客户端。我们在这里发送一个字符串,但是你也可以发送一个ArrayBufferBlob Node.js Buffer,甚至File的实例。还可以发送一个简单的 JavaScript 对象。
  • 然后,我们为message事件附加了一个事件处理程序,当 Socket。输入输出客户端向套接字发送消息。IO 服务器。
  • 之后,我们给disconnect事件附加了一个事件处理程序,当 Socket。输入输出客户端与套接字断开连接。IO 服务器。
  • socket对象的emit方法用于向套接字发送自定义事件。IO 客户端。它可以接受无限多的参数。它采用的第一个参数是事件名称,其余参数是事件处理程序的参数,该事件处理程序是在套接字上触发的。IO 客户端。
  • 最后,我们使用socket对象的on()方法为名为custom-event的自定义事件注册一个事件处理程序。

现在,我们已经创建了一个非常简单的套接字。让套接字。输入输出客户端与之建立连接。它也在听messagecustom-event事件。它还发送一条消息,并向套接字发出一个自定义事件。一旦连接上 IO 客户端。

就像每个插座一样。输入输出客户端在套接字上获得一个单独的socket对象。IO 服务器,如果我们想要一个socket对象能够访问另一个 Socket 的socket对象。IO 客户端,那么我们可以保留对每个 Socket 的socket对象的引用。全局阵列中的输入输出客户端。如果我们正在创建一个聊天应用,其中一个socket对象需要访问另一个socket对象才能向其发送消息,这将非常有用。

现在可以运行套接字了。IO 服务器使用node socket.js命令。

现在,让我们构建套接字。IO 客户端。下面是创建套接字的代码。输入输出客户端实例并建立一个套接字。与插座的输入输出连接。IO 服务器。将该代码放入index.html文件的<script>标签中:

var socket = io("http://localhost:3000", {path: "/websocket"});

在这里,我们首先创建一个套接字。输入输出客户端实例,并与套接字建立连接。IO 服务器使用io构造函数。第一个参数是套接字的基本网址。IO 服务器。第二个参数是一个可选对象,我们已经向它传递了握手请求应该到达的 URL 路径。如果不经过路径,那么默认路径就是/socket.io

我们创建了一个单一的套接字。这里是 IO 客户端实例,但是我们可以自由创建多个 Socket。如果我们想连接到多个套接字,请使用 IO 客户端实例。IO 服务器。

我们在这里使用http方案而不是ws方案,因为 Socket。IO 可以使用除 WebSocket 之外的任何技术或协议来实现双向通信。如果插座。IO 选择使用 WebSocket,则自动将http替换为ws

让我们写一些代码在套接字上做一些事情。套接字后的输入输出客户端。IO 连接已经建立。将该代码放入index.html文件的<script>标签中:

socket.on("connect", function () {

  socket.send("Hi, from client");

  socket.on("message", function (msg) {
    console.log(msg)
  });

  socket.on("disconnect", function(){ 
    console.log("I am disconnected");
  });

  socket.on("custom-event", function (parameter1, parameter2) {
    console.log(parameter1, parameter2);
  });

  socket.emit("custom-event", "parameter1", "parameter2");
});

让我们了解一下这段代码是如何工作的,以及send()on()emit()方法的作用:

  • socket对象的on()方法用于将事件处理程序附加到套接字上触发的事件。IO 客户端本身。
  • 我们首先给connect事件附加一个事件处理程序。只要一个插座。IO 连接已经建立,connect事件被触发。
  • send()方法的socket对象用于向套接字发送消息。IO 服务器。我们在这里发送一个字符串,但是你也可以发送一个ArrayBufferBlob甚至File的实例。还可以发送一个简单的 JavaScript 对象。
  • 然后,我们给message事件附加了一个事件处理程序,当 Socket。输入输出服务器向套接字发送消息。IO 客户端。
  • 然后,我们将一个事件处理程序附加到disconnect事件,当套接字。输入输出客户端与套接字断开连接。IO 服务器。只要一个插座。输入输出连接中断,插座。IO 客户端不断尝试自动重新连接。
  • 之后,我们使用socket对象的on()方法为名为custom-event的自定义事件注册一个事件处理程序。
  • socket对象的emit方法用于向套接字发送自定义事件。IO 服务器。它可以接受无限多的参数。它采用的第一个参数是事件名称,其余参数是事件处理程序的参数,该事件处理程序在套接字中触发。IO 客户端。

现在,在浏览器中打开 URL http://localhost:8080/,应该会看到如下控制台输出:

Hi, from server
parameter1 parameter2

您将在运行套接字的外壳中看到以下输出。输入输出服务器:

Hi, from client
parameter1 parameter2

基于原点限制连接

默认情况下,一个插座。输入输出服务器让套接字。任何来源的输入输出客户端都建立一个套接字。与它的 IO 连接。插座。IO 提供了一种将连接限制在特定来源的方法。

要将连接限制到特定的原点或一组原点,我们可以使用Server实例的origins方法。

将该代码放入socket.js文件,只允许 Socket。运行在localhost域和端口号8080上的输入输出客户端连接到套接字。输入输出服务器:

io.origins("localhost:8080");

我们不能简单地将任何origin传递给origins方法。以下是一些有效的例子origins:

  • testsite.com:80
  • http://testsite.com:80
  • http://*:8080 (*是通配符)
  • *:8080
  • testsite.com:* http://someotherdomain.com:8080(由空格分隔的多个原点)
  • testsite.com:*/somepath(插座。IO 将忽略/某些路径)
  • *:*

在之前的列表中,每个原点都有一个与之关联的端口号,因为必须提供一个端口号或*来代替端口号,表示任何端口。

以下是无效起源的一些例子:

  • testsite.com
  • http://testsite.com
  • http://testsite.com/somepath

这些是无效的,因为它们没有关联的端口号。

还要注意,如果指定sub.testsite.com作为origins值,testsite.com将是一个有效的原点。

套接字中的命名空间。超正析象管(Image Orthicon)

插座。IO 服务器实际上是划分成子服务器称为命名空间。插座。IO 客户端总是连接到一个命名空间。每个名称空间都有一个名称,看起来像一个 HTTP 路径。

在前面的代码中,当我们创建一个套接字时。IO 服务器,已创建默认命名空间。默认命名空间由/路径标识。如果我们在创建套接字时没有提到命名空间。IO 客户端,然后它连接到默认命名空间。因此,connection事件特定于一个特定的名称空间,也就是说,对于每个名称空间,我们必须注册一个不同的connection事件处理程序。

类型

名称空间有什么好处?

您一定想知道引入名称空间有什么意义。名称空间让编写复杂的代码变得更加容易。让我们看一个例子来理解这一点。

假设您有一个网页,其中包含多个实时更新的组件。然后,您将创建多个套接字。一个组件的输入输出服务器或使用单个套接字。IO 服务器并依靠数据格式的一条消息或自定义事件来查找哪些数据属于哪个组件。这两种技术都有缺点,即创建多个套接字。IO 服务器占用多个端口,不适合大量组件,依赖消息和自定义事件的数据格式,很难将前端组件移动到单独的应用,因为新应用会得到大量不必要的消息和事件,造成双方的带宽问题。因此,引入了名称空间,它结合了两种技术的优点,同时忽略了它们的缺点。

下面是如何创建自定义命名空间。将该代码放入socket.js文件:

var nsp = io.of("/custom-namespace");

nsp.on("connection", function(socket){
  socket.send("Hi, from custom-namespace");

  socket.on("message", function(message){
    console.log(message);
  });

  socket.on("disconnect", function(){ 
    console.log("User Disconnected");
  });

  socket.on("custom-event", function (parameter1, parameter2) {
    console.log(parameter1, parameter2);
  });

  socket.emit("custom-event", "parameter1", "parameter2");
});

将这段代码添加到socket.js文件后,我们将有两个名称空间,即我们之前创建的默认名称空间和这个名为/custom-namespace的名称空间。在这里,您可以看到我们为这个名称空间注册了一个新的连接事件处理程序。

现在,让我们创建另一个套接字。输入输出客户端,连接到/custom-namespace命名空间。将该代码放入index.html文件的<script>标签中:

var socket1 = io("http://localhost:3000/custom-namespace", {path: "/websocket"});

socket1.on("connect", function () {

  socket1.send("Hi, from client");

  socket1.on("message", function (msg) {
    console.log(msg)
  });

  socket1.on("disconnect", function(){ 
    console.log("I am disconnected");
  });

  socket1.on("custom-event", function (parameter1, parameter2) {
    console.log(parameter1, parameter2);
  });

  socket1.emit("custom-event", "parameter1", "parameter2");
});

在这里,我们正在创建另一个套接字。IO 客户端;这个连接到/custom-namespace命名空间。

现在,重新运行文件并访问http://localhost:8080/。这将是浏览器控制台输出:

Hi, from server
parameter1 parameter2
Hi, from custom-namespace
parameter1 parameter2

这将是新的 shell 输出:

Hi, from client
parameter1 parameter2
Hi, from client
parameter1 parameter2

当我们使用origins()方法基于原点限制访问时,它应用于所有名称空间。

指所有连接的插座。输入输出客户端

插座。IO 服务器 API 还为我们提供了一种向命名空间中的每个人发送消息或自定义事件的方式。

让我们看一个如何做到这一点的例子。将以下代码放入socket.js文件:

setInterval(function(){
  //sending message and custom-event-2 to all clients of default namespace
  io.emit("custom-event-2");
  io.send("Hello Everyone. What's up!!!");

  //sending message and custom-event-2 to all clients of /custom-namespace namespace
  nsp.emit("custom-event-2");
  nsp.send("Hello Everyone. What's up!!!");
}, 5000)

在这里,向所有套接字发送消息或自定义事件。IO 客户端连接到默认的命名空间,我们使用io对象。并将其发送给 Socker。连接到自定义命名空间的 IO 客户端,我们使用of()方法返回的对象。

在这里,我们只是每隔5秒向两个名称空间中的每个人发送一条消息和自定义事件。

插座中的房间。超正析象管(Image Orthicon)

一个房间简单来说代表一组 Socket。IO 客户端将连接到特定的命名空间。房间属于特定的命名空间。

一个命名空间不能有两个同名的房间,但是两个不同的命名空间可以有同名的房间。不同名称空间上同名的房间完全是不同的房间。

每个插座。连接到命名空间的 IO 客户端必须属于一个或多个组。默认情况下,当套接字。连接 IO 客户端后,会创建一个新组,并将客户端添加到该组中。因此,每个套接字。默认情况下,IO 客户端属于一个唯一的组。

下面是打印套接字的唯一组名的代码。连接后的输入输出客户端。将其放入默认的和/custom-namespace命名空间的connection事件处理程序中:

console.log(socket.id);

socket对象的id属性保存唯一的房间名称。

加入和离开房间

要添加一个插座。IO 客户端到一个自定义房间,我们需要使用socket.use()方法。移除插座。来自定制房间的 IO 客户端,我们需要使用socket.leave()方法。

下面的代码添加了每个套接字。IO 客户端连接到默认的/custom-namespace服务器到一个名为my-custom-room的房间。将其放入默认的/custom-namespace命名空间的connection事件处理程序中:

socket.join("my-custom-room");

同样,要从my-custom-room中删除用户,可以使用以下代码:

socket.leave("my-custom-room");

指所有连接的插座。房间里的输入输出客户端

插座。IO 服务器 API 还为我们提供了一种向房间中的每个人发送消息或自定义事件的方式。

让我们看一个如何做到这一点的例子。将以下代码放入socket.js文件:

setInterval(function(){
  //sending message and custom-event-3 to all clients in my-custom-room room of default namespace
  io.to("my-custom-room").send("Hello to everyone in this group");
  io.to("my-custom-room").emit("custom-event-3");

  //sending message and custom-event-3 to all clients in my-custom-room room of /custom-namespace namespace
  nsp.to("my-custom-room").send("Hello to everyone in this group");
  nsp.to("my-custom-room").emit("custom-event-3");
}, 5000)

在这里,向所有套接字发送消息或自定义事件。IO 客户端在my-custom-room房间的默认命名空间,我们需要使用io.to().send()方法。并向所有套接字发送消息或自定义事件。在/custom-namespace命名空间的my-custom-room房间中的 IO 客户端,我们需要使用nsp.to().send()方法。

向名称空间和房间广播消息和自定义事件

广播是 Socket 的一个特色。IO 服务器 API,允许一个socket对象发送消息或自定义事件给名字空间或房间中的每个人,除了它自己。

广播到命名空间

向所有套接字广播消息。一个命名空间中的 IO 客户端,我们需要使用socket.broadcast.send()方法,而要广播一个自定义事件,我们需要使用socket.broadcast.emit()方法。

我们来看一个例子。将以下代码放入默认名称空间的connection事件处理程序中,以便在每次新套接字时广播一条消息。输入输出客户端加入:

socket.broadcast.send("A new user have joined");

现在,在两个不同的选项卡中打开http://localhost:8080/。在第一个选项卡的控制台中,您将看到以下输出:

Hi, from server
parameter1 parameter2
Hi, from custom-namespace
parameter1 parameter2
A new user have joined

在第二个选项卡的控制台中,您将看到以下输出:

Hi, from server
parameter1 parameter2
Hi, from custom-namespace
parameter1 parameter2

向房间广播

向所有套接字广播消息。一个房间里的 IO 客户端,我们需要使用socket.broadcast.to().send()方法,而要广播一个自定义事件,我们需要使用socket.broadcast.to.emit()方法。

将此代码放在默认和/custom-namespace命名空间的connection事件处理程序中:

socket.broadcast.to("my-custom-room").send("Hi everyone. I just joined this group");

这里,只要一个插座。IO 客户端是连接的,它向房间里的其他人发送消息。

记住,插座。IO 客户端不必是房间的成员就可以向它的套接字广播消息。输入输出客户端。

Socket 中的中间件。超正析象管(Image Orthicon)

套接字中的中间件。输入输出服务器是一个回调,当套接字。IO 客户端在套接字之前发出握手请求。IO 服务器回复它。中间件允许我们允许或拒绝握手。

套接字的中间件概念。IO 和 Express 类似,不同的是中间件没有获得 HTTP 响应对象的访问权限;还有,parameter的签名不一样。因此,Express 中间件不能在 Socket.IO 中使用

中间件的一个实例被附加到一个特定的名称空间。下面是一个基本示例,演示了如何向所有名称空间注册中间件实例。将该代码放入Socket.IO文件:

io.use(function(socket, next) {  
  //request object
  //socket.request

  //to reject
  //next(new Error("Reason for reject"));

  //to continue
  next();
});

在这里,我们可以看到我们需要使用io.use()方法向所有名称空间注册一个中间件实例。要将中间件附加到/custom-namespace名称空间,我们可以使用nsp.use()方法。

手动断开

您也可以手动断开插座。IO 连接。要断开与客户端的连接,需要使用io实例的disconnect()方法。要从服务器端断开连接,您需要使用socket.disconnect()方法。

总结

在本章中,我们学习了网络套接字协议的基础。我们了解了它与 HTTP 的关系,以及它与代理、负载平衡器和防火墙的关系。然后,我们跳进了插座。IO 库,主要利用 WebSocket 实时实现双向全双工通信。您应该对实现浏览器和 Node.js 服务器之间的双向通信感到满意。

在下一章中,我们将使用 Socket.IO 构建一个真实世界的应用。您将学习更高级的东西,例如集成一个 Socket。带有快速服务器的输入输出服务器,并在连接到网络套接字服务器之前检查身份验证。