如何使用Node.js和Docker的可扩展消息和存在协议 - XMPP

149 阅读7分钟

使用Node.js和Docker的可扩展消息和存在协议--XMPP

可扩展消息与存在协议(XMPP)是一个开放的通信协议,用于即时通信的存在信息和联系人列表的维护。

本教程将带领你了解XMPP架构的概念,它是如何工作的,并使用Node.jsdocker建立一个演示服务器连接。

前提条件

要轻松地跟上本教程,应该满足以下要求。

  • 对Node.js的编程和Docker命令有基本的了解。
  • 一个预装的IDE,最好是[Visual Studio Code]。
  • 对[Docker]有基本的了解。
  • 对[Node.js]有基本的了解。

主要收获

在本教程结束时,你应该明白。

  • 为什么我们需要XMPP?
  • 底线架构和它的工作原理。
  • XMPP传输。
  • 使用Node.js和Docker的XMPP服务器演示。

为什么是XMPP?

XMPP是Extensible Messaging and Presence Protocol的缩写,是一个开放的标准,通过管理网络上的XML数据交换,支持近实时的聊天和即时通讯。

XMPP允许XML数据,以短文段的形式,使用互联网的传输控制协议(TCP)从一个终端可靠地发送到另一个终端,沿途要经过一个中间服务器。

XML,即可扩展标记语言,提供了一个框架,用于存储和组织文档中的纯文本数据,这样,无论其硬件或软件配置如何,这些数据都可以被各种网络终端轻松解释。

当在后端使用时,它给出了一个直接的链接,几个客户通过它进行连接。它有一个分散的协议,允许属于不同的XMPP服务器的客户与它进行通信。

XMPP架构

在这一节中,让我们看看这项技术的架构和它的内部工作方式。为了便于在网络上进行路由,所有的XMPP地址都是全球可寻址的。

它的设计是使用XML流标签,即<stream:stream /> 。这是通过在每个元素中发送XML句子来实现的,而不需要等待整个文件被完全发送。

还有一种通过询问客户是否支持某种类型的协议、加密等功能的协商。同样,这可以在XMPP协议的基础上完成。

XMPP支持三种不同的XML句子。

以下是这些句法。

  1. 消息可以用XML标签发送。
  2. 状态也可以像这样进行交换。
  3. 信息查询,这是请求-回应的liketag。

最后,整个XMPP是分散的。这意味着没有一个客户端是直接连接到另一个客户端的。相反,连接是由服务器作为客户端之间的中介来实现的。

让我们假设我们有一个域名myxmpp.com 作为两个客户之间的服务器。下面的例子显示了如何建立连接。

ClientA 连接到xmpp服务器。

    <stream:stream
    from='a@myxmpp.com'
    to='myxmpp.com'
    version='1.0'
    xmlns='jabber:client'
    >

而另一个客户,ClientB 连接到xmpp服务器。

    <stream:stream
    from='b@myxmpp.com'
    to='myxmpp.com'
    version='1.0'
    xmlns='jabber:client'
    >

ClientA 通过服务器向 发送一个消息。ClientB

<message to='b@myxmpp.com'>
    <body>Hello  </body>
</message>

然后ClientB 收到来自ClientA 的消息,如下所示。

<message from='a@myxmpp.com'>
    <body>Hi </body>
</message>

客户端A终止了流。

</stream:stream>

上面的代码片段显示了这个XMPP服务器的结构。这就是服务器如何通过使用定义的stream 的属性来连接不同的客户端。

每个流标签都有from,to,versionxmlns 参数。是服务器根据注册时提供的客户详细资料预先填入这些参数的。

不用担心,当我们建立一个演示时,所有这些很快就会被清除掉。

XMPP传输

XMPP是建立在传输控制协议TCP 上的一种不可知的传输方式。服务器运行的默认端口是5222 。这个服务器可能会被防火墙屏蔽,因为它不喜欢随机端口。

通过在HTTP上托管XMPP服务器,并进行长时间的轮询,可以避免这种情况,因为它只在服务器收到新的请求时发送消息。也就是说,HTTP不是双向的,是无状态的。

使用Node.js和docker的XMPP服务器演示

在这个演示中,我们用docker旋转了XMPP服务器ejabberd ,因为这是最简单的方法。我们将创建两个用户,启动Node.js XMPP客户端以连接到服务器,然后进行聊天。我们必须使用下面的命令创建一个ejabberd 实例图像。

docker run --name ejabberd -p 5222:5222 ejabberd/ecs

上面的命令将运行ejabberd ,XMPP服务器在端口5222 ,并创建其docker镜像与ejabberd/ecs

现在继续并打开另一个终端,用下面的docker命令注册这两个客户端。

docker exec -it ejabberd  bin/ejabberdctl register admin localhost mypassword1

Docker使用ejbberd/bin/ejabberdctl ,用提供的凭证注册一个新的用户。关键字admin 是第一个用户的名字。而localhost ,则是指向你机器的本地IP。

注意:如果需要另一个IP地址,这可以被改变。然而,现有的域名也可以使用。

注册成功后,它将返回一个信息User admin@localhost successfully registered

注意,根据你的设置,输出结果可能有所不同。

此外,我们将用同样的程序注册另一个用户。

docker exec -it ejabberd  bin/ejabberdctl register myself localhost mypassword2

注册成功后,会返回一个消息User user2@localhost successfully registered 。那么,我们如何将这两个客户端与服务器连接起来呢?

这就是Node.js的作用。我们使用该框架来编写客户端之间连接的服务器代码。

打开你喜欢的代码编辑器,创建一个Node.js项目,如下所示。

$ npm init .
$ npm install simple-xmpp

上面的JavaScript代码片段创建了一个新的项目目录,其中包含package.json 文件。这个文件跟踪你的项目所需的所有依赖性。

安装的simple-xmpp 是在不同客户端之间启动XMPP服务器连接所需的库。由于没有给出--save-dev 命令,所以这是全局安装的。

在有package.json 的项目目录下,创建admin.jsmyself.js 文件。我们用服务器-客户端连接来编辑这些文件。

admin.js 的代码在下面的片断中给出。

// we bring in the server library
const xmpp = require("simple-xmpp"); 

// this function recursively call itself by sending the provided message every 5 seconds.
function send(){
    setTimeout(send, 5000);
    xmpp.send("myself @localhost", `hi! Today is ${new Date().toLocaleString()}`)
}

//if online, that is connected to the server the send function will be excuted and log to console
xmpp.on("online", data => {
    console.log("hello, you are live!");
    console.log(`Connected as ${data.jid.user}`);
    send();
});

// if chat was received from other client, the log will be executed
xmpp.on("chat", (from, message) => {
    console.log(`Got a message! ${message} from ${from}`)
})

// connect method requires object with paramters below
xmpp.connect({
    "jid": "admin@localhost",
    "password": "mypassword1",
    "host": "localhost",
    "port": 5222
})

simple-xmpp 库有不同的参数被调用。例如,在上面的代码片段中,我们在onlinechat 的参数上调用了on 方法。

一旦管理员用户连接到服务器,on 方法就会将连接识别为online ,并执行回调函数。

然而,该库的on 方法只有在收到其他客户端的任何消息时才会执行chat 参数的回调函数。simple-xmpp 库有connect() 方法,需要不同的属性。

jid 作为每个客户端的身份,这是从上面的注册中返回的。所有其他参数是passwordhost ,和port

另一个客户端也需要同样的连接,但参数不同。因此,在下面找到myself.js 文件的片段。

const xmpp = require("simple-xmpp"); 

function send(){
    setTimeout(send, 5000);
    xmpp.send("admin@localhost", `hi! Today is ${new Date().toLocaleString()}`)
}

xmpp.on("online", data => {
    console.log("hello, you are live!");
    console.log(`Connected as ${data.jid.user}`);
    send();
});

xmpp.on("chat", (from, message) => {
    console.log(`Got a message! ${message} from ${from}`)
})

xmpp.connect({
    "jid": "myself@localhost",
    "password": "mypassword2",
    "host": "localhost",
    "port": 5222
})

现在,打开到不同的代码编辑器终端,运行下面的命令。确保你cd ,进入项目目录。

从第一个终端,运行下面的代码。

node admin.js

运行这个命令后,你将收到从on() 方法的online 参数中记录的信息。

该日志信息将是这样的。

Hey, you are online!
Connected as user1

在第二个终端运行这个命令,会调用另一个客户-服务器。

node myself.js

现在,两个客户端都连接了,send() 函数的消息体将开始每隔5 秒向两个连接弹出。有了这个连接,我们就实现了本教程的目标。

总结

本教程介绍了意义的概念,下划线架构,以及XMPP服务器如何工作。我们还使用Node.js建立了一个演示连接,并使用docker来旋转服务器镜像来注册客户端。