跳至主内容

如何使用 WebSockets 组合应用程序

·阅读时长4分钟
Marek Majkowski

或者:如何在 WebSockets 或 SockJS 上正确实现多路复用

正如您可能知道的,WebSockets 是一项很棒的新 HTML5 技术,它允许您异步发送和接收消息。我们的兼容性层 - SockJS - 模拟了它,即使在旧浏览器或代理后面也能正常工作。WebSockets 在概念上非常简单。API 主要包括:连接、发送和接收。但是,如果您的 Web 应用程序有许多模块,并且每个模块都想要发送和接收数据,该怎么办?

理论上,您可以为每个模块打开多个 WebSocket 连接。虽然不是最优选择(因为需要处理多个 TCP/IP 连接),但这种方法对原生 WebSocket 有效。然而,不幸的是,由于 HTTP 的技术限制,它对 SockJS 无效:对于某些回退传输,无法一次连接到单个服务器打开多个连接。这个问题是真实存在的,值得解决。让我重新表述一下:

假设您只能与给定主机建立一个连接,并且有多个模块希望发送和接收数据,您该怎么做?

您需要复用:将来自多个源的数据合并到一个连接中。下一个问题是您使用什么 API;您如何在代码中暴露复用?

Socket.io 的方式

Socket.io 有一个 API 试图解决这个问题,它称之为“命名空间”。下面是一些客户端(浏览器)示例代码:

var chat = io.connect('https:///chat');
chat.on('connect', function () {
chat.emit('hi!');
});

var news = io.connect('https:///news');
news.on('news', function () {
news.emit('woot');
});

我认为这个 API 相当令人困惑——Socket.io 在底层只打开了一个连接,但阅读代码会给我们带来不同的感受。

SockJS 的方式

与 Socket.io 不同,SockJS 没有什么神奇的 API。它看起来像一个 WebSocket 对象,行为也像一个。没什么令人惊讶的。

那么如何解决复用问题呢?

通常,最好避免创建新 API,而是使用已有的 API。为什么不将每个复用的通道呈现为一个 WebSocket 对象呢?

我建议的方法非常简单——您获取一个真实的 SockJS(或 WebSocket)连接,将其包装在一个复用层中,然后从中提取任意数量的虚假 WebSocket 对象。它们将在内部进行复用,但从模块的角度来看——这是完全透明的。就模块而言,它与一个 WebSocket 对象进行通信。

就是这样。这有点像魔术师的帽子。您放入一个 WebSocket 连接,可以取出任意数量的虚假 WebSocket 连接。

这种方法比 Socket.io 提出的要好——您可以创建仅依赖原生 WebSocket API 的代码。之后,当需要出现时,您只需将一个虚假的 WebSocket 对象而不是真实的传递过去。换句话说:它可以组合。问题解决了。

实现

如果在浏览器中之前使用的是单个 SockJS 连接,如下所示:

var sockjs = new SockJS('/echo');

您可以修改客户端代码为:

var real_sockjs = new SockJS('/echo');

var multiplexer = new WebSocketMultiplex(real_sockjs);
var fake_sockjs_1 = multiplexer.channel('ann');
var fake_sockjs_2 = multiplexer.channel('bob');

此时,“虚假”对象将与普通的 SockJS 对象行为相同。您可以预期会收到“open”、“message”和“close”事件。(底层代码大约有 60 行 JavaScript)同样,服务器端——它通常使用普通的“net.Server”和“Stream”Node API。

var service = sockjs.createServer();

更改后:

var real_service = sockjs.createServer();

var multiplexer = new multiplex_server.MultiplexServer(real_service);
var fake_service_1 = multiplexer.registerChannel('ann');
var fake_service_2 = multiplexer.registerChannel('bob');

再次,“虚假”对象将执行正常操作,当用户订阅特定频道时,它们将发出“connected”事件。(底层复用器代码也不复杂

如果您想看看复用器代码的实际应用:

最后的想法

值得强调的是,这种方法确实具有组合性。任何模块都可以获取一个虚假的 WebSocket 对象并重复此技巧来获取更多的第二层虚假 WebSocket 对象。不要发明新 API,只需创建依赖于传递给构造函数的 WebSocket 实例的代码。这才是您使用 WebSockets 创建可组合代码真正需要的东西!

© . This site is unofficial and not affiliated with VMware.