关于 libwebsockets:WebSockets 服务器架构是如何工作的?

How does WebSockets server architecture work?

我试图更好地理解服务器端架构如何用于 WebSockets,目标是在嵌入式应用程序中实现它。似乎这里有 3 个不同的服务器端软件组件在起作用:1) 用于服务静态 HTTP 页面并处理升级请求的 Web 服务器,2) 一个 WebSockets 库,例如 libwebsockets,用于处理 WebSockets 通信的"具体细节" , 和 3) 我的自定义应用程序来实际弄清楚如何处理传入的数据。所有这些如何结合在一起?有一个单独的 Web 服务器和 WebSocket 处理件,也就是一个 WebSocket 服务器/守护进程,这很常见吗?

我的应用程序如何与 Web 服务器和/或 WebSockets 库通信以发送/接收数据?例如,使用 CGI,Web 服务器使用环境变量向自定义应用程序发送信息,并使用标准输出接收响应。这里的等效通信系统是什么?还是您通常将 WebSocket 库链接到客户应用程序?但是,Web 服务器与 WebSocket 库自定义应用程序的通信将如何工作呢?还是全部 3 个组合成一个组件?

这就是我要问的原因。我在内存有限的 Blackfin 处理器上的 uClinux/no MMU 平台上使用 boa Web 服务器。 boa 中没有原生 WebSocket 支持,只有 CGI。我试图弄清楚如何向其中添加 WebSockets 支持。我更喜欢使用编译的解决方案,而不是解释的东西,如 JavaScript、Python 或 PHP。我当前的应用程序在 CGI 上使用长轮询,它不能为计划的增强提供足够的性能。


首先,了解如何建立 webSocket 连接很重要,因为这对 webSocket 连接和您的 Web 服务器之间的关系非常重要。

每个 webSocket 连接都以一个 HTTP 请求开始。浏览器向请求 webSocket 连接的主机/端口发送 HTTP 请求。该请求可能如下所示:

1
2
3
4
5
6
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

此请求与对该服务器的任何其他 HTTP 请求的区别在于请求中的 Upgrade: websocket 标头。这告诉 HTTP 服务器这个特定的请求实际上是一个发起 webSocket 连接的请求。此标头还允许 Web 服务器区分常规 HTTP 请求和打开 webSocket 连接的请求。这允许在架构中进行一些非常重要的事情,并且完全是故意这样做的。这允许使用完全相同的服务器和端口来为您的 Web 请求和 webSocket 连接提供服务。所需要的只是您的 Web 服务器上的一个组件,该组件在所有传入的 HTTP 连接上查找此 Upgrade 标头,如果找到,它将接管连接并将其转换为 webSocket 连接。

一旦服务器识别出这个 Upgrade 标头,它会以合法的 HTTP 响应进行响应,但会向客户端发出信号表明已接受对 webSocket 协议的升级,如下所示:

1
2
3
4
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

此时,客户端和服务器都将原始 HTTP 请求中的套接字保持打开状态,并切换到 webSocket 协议。

现在,针对您的具体问题:

How does my application communicate with the web server and/or
WebSockets library to send/receive data?

您的应用程序可以使用现代浏览器中内置的 webSocket 支持,并且可以像这样启动 webSocket 连接:

1
var socket = new WebSocket("ws://www.example.com");

这将指示浏览器启动到 www.example.com 的 webSocket 连接,使用与当前网页连接的相同端口。由于浏览器内置了 webSocket 支持,上述 HTTP 请求和升级协议由客户端自动为您处理。

在服务器端,您需要确保您使用的 Web 服务器具有传入的 webSocket 支持,并且支持已启用和配置。因为一个 webSocket 连接一旦建立起来就是一个持续的连接,它根本不遵循 CGI 模型。必须至少有一个长时间运行的进程来处理实时 webSocket 连接。在服务器模型(如 CGI)中,您需要某种 webServer 插件来支持您的 webSocket 连接的这种长时间运行的过程。在像 node.js 这样已经是一个长期运行的进程的服务器环境中,添加 webSockets 在架构上根本没有改变——而只是一个支持 webSocket 协议的附加库。

我建议您可能会发现这篇文章很有趣,因为它讨论了从 CGI 样式的单一请求处理到 webSocket 的连续套接字连接的转变:

Web Evolution:从 CGI 到 Websockets(以及它将如何帮助您更好地监控您的云基础设施)

如果你真的想坚持使用标准输入/标准输出模型,有一些库可以为你的 webSockets 建模。这是一个这样的图书馆。他们的标语是"它就像 CGI,二十年后,对于 WebSockets"。

I'm trying to figure out how I can add WebSockets support to that. I
would prefer to use a compiled solution as opposed to something
interpreted such as JavaScript, Python or PHP.

抱歉,我不熟悉那个特定的服务器环境。可能需要进行一些深入的搜索才能找出您的选择。由于 webSocket 连接是连续连接,因此您将需要一个连续运行的进程,该进程可以是 webSocket 连接的服务器端部分。这可以是您的 webServer 中内置的东西,也可以是 webServer 启动并将传入连接转发到的附加进程。

仅供参考,我在家里有一个基于 Raspberry Pi 的自定义应用程序,它使用 webSockets 与浏览器网页进行实时通信,它工作得很好。我碰巧将 node.js 用于服务器环境和在 webSockets 之上运行的 socket.io 库,以便在 webSockets 之上为我提供更高级别的接口。我的服务器代码会定期检查几个硬件传感器,然后每当有新的/更改的数据要报告时,它就会向任何打开的 webSockets 发送消息,以便连接的浏览器获得传感器读数的实时更新。

您可能需要一些长时间运行的应用程序,将传入的 webSocket 连接从 web 服务器传递到长时间运行的进程,或者您需要在与 web 服务器不同的端口上建立 webSocket 连接(这样他们就可以由完全不同的服务器进程处理)在这种情况下,您将拥有一个完全独立的服务器来处理您的 webSocket 请求和套接字(该服务器还必须支持 CORS 以使浏览器能够连接到它,因为它会是一个不同的端口比您的网页)。