Subscribe to receive notifications of new posts:

Subscription confirmed. Thank you for subscribing!

通过 TCP and Sockets for Workers 建立连接

Loading...

Making connections with TCP and Sockets for Workers

今天,我们很高兴地宣布,我们正在开发 API 和基础结构以在 Cloudflare Workers 中支持更多基于 TCP、UDP 和 QUIC 的协议。一旦发布,这些新功能有可能实现使用非 HTTP 套接字与 Worker 或 Durable Object 互相连接,就像我们如今使用 HTTP 和 WebSockets 一样简单。

目前,Cloudflare Workers 支持使用标准化的 fetchWebSocket API 打开 HTTP 和 WebSocket 连接的功能。通过在内部进行一些更改使其可在 Workers 中运作,我们制作了一个示例,使用现有的驱动程序(在本示例中,是基于 Deno 的 Postgres 客户端驱动程序)通过 WebSocket(通过安全的 Cloudflare Tunnel)与远程 Postgres 服务器通信。

import { Client } from './driver/postgres/postgres'

export default {
  async fetch(request: Request, env, ctx: ExecutionContext) {
    try {
      const client = new Client({
        user: 'postgres',
        database: 'postgres',
        hostname: 'https://db.example.com',
        password: '',
        port: 5432,
      })
      await client.connect()
      const result = await client.queryArray('SELECT * FROM users WHERE uuid=1;')
      ctx.waitUntil(client.end())
      return new Response(JSON.stringify(result.rows[0]))
    } catch (e) {
      return new Response((e as Error).message)
    }
  },
}

此示例的工作方式是,使用标准 fetch 和 WebSockets API 替换使用 Deno 特定 TCP 套接字 API 的 Postgres 客户端驱动程序的位数。然后,我们建立了与一个远程 Cloudflare Tunnel 守护程序的 WebSocket 连接(该守护程序在 Postgres 服务器附近运行),从而建立有效的 TCP-over-WebSockets。

Connecting to a backend data center via a Cloudflare Tunnel
Connecting to a backend data center via a Cloudflare Tunnel

尽管在无需对 Cloudflare Workers 运行时进行任何更改的情况下,我们能够构建出该示例并和 Postgres 服务器有效且高效地通信这一事实令人印象深刻,但这一方法存在许多限制。第一点是,该解决方案需要额外的基础结构来建立和维护 WebSocket 通道,在本示例中,是在 Postgres 服务器附近运行的 Cloudflare Tunnel 守护程序的实例。当然,我们很乐意向客户提供该守护程序,但如果根本不需要该组件,那自然更好。第二点是,通过 WebSockets 隧道传输 TCP,其本身是通过 HTTP over TCP 进行隧道传输,这并非最优解。这可以运作,但我们可以做得更好。

从 Cloudflare Workers 进行连接

目前,没有标准 API 用于 JavaScript 中的套接字连接。我们想要改变此状况。

如果您之前使用过 Node.js,那么您极有可能熟悉 net.Socketnet.TLSSocket 对象。如果您使用 Deno,那么您可能知道他们最近引入了 Deno.connect()Deno.connectTLS() API。当您查看这些 API,立即就能发现它们彼此之间的差别有多大,尽管它们都是用来做完全相同的事情。

当我们决定添加从 Workers 中打开和使用套接字连接的功能时,我们也一致认为,我们的确没有兴趣开发另一个特定于平台且与其他平台所提供之 API 不同的非标准 API。因此,我们将邀请扩展到需要套接字功能的所有 JavaScript 运行时平台,以合作开发新的(且最终标准化的)API,无论您选择在哪个运行时上进行开发,该 API 都可以运作。

下面是我们构想用于从单个 TCP 客户端连接打开和读取内容的大致示例:

const socket = new Socket({
  remote: { address: '123.123.123.123', port: 1234 },
})
for await (const chunk of socket.readable)
  console.log(chunk)

或者,此示例使用 UDP 发送一个简单的“hello world”数据包:

const socket = new Socket({
  type: 'udp',
  remote: { address: '123.123.123.123', port: 1234 },
});
const enc = new TextEncoder();
const writer = socket.writable.getWriter();
await writer.write(enc.encode('hello world'));
await writer.close();

该 API 将设计得足够通用,能够与客户端和服务器端合作;可用于 TCP、UDP 和 QUIC;具有或不具有 TLS,且不会依赖于特定于任何单一 JavaScript 运行时的任何机制。它将在现有广泛支持的 Web 平台标准基础上构建,例如 EventTargetReadableStreamWritableStreamAbortSignalpromises。原本熟悉 fetch() API、service workers 和使用 async/await 的 promises 的开发人员都会熟悉该新 API。

interface Socket : EventTarget {
  constructor(object SocketInit);

  Promise<undefined> update(object SocketInit);

  readonly attribute ReadableStream readable;
  readonly attribute WritableStream writable;
  
  readonly attribute Promise<undefined> ready;
  readonly attribute Promise<undefined> closed;

  Promise<undefined> abort(optional any reason);
  readonly attribute AbortSignal signal;
 
  readonly attribute SocketStats stats;
  readonly attribute SocketInfo info;
}

这目前还只是一个提议,在 Workers 中实际交付该功能时,详细信息很可能会与上述示例有所不同。我们希望其他平台能够加入我们,共同开发和支持这一新 API,以便开发人员拥有一个一致的构建基础,而不论其在哪里运行其代码。

引入 Socket Workers

打开套接字客户端连接的功能只是这个构想的一半。

当我们第一次谈论添加这些功能时,就提出了一个明显的问题:使用非 HTTP 协议连接 Workers 会怎么样?如果不只是能够将一个 Worker 连接到一些其他后端数据库,还可以在边缘、Worker 内部实施整个数据库,并让非 HTTP 客户端连接到它,会怎么样?对于这种情况,如果我们可以在 Workers 中实施一个 SMTP 服务器,会怎么样?或者是一个 MQTT 信息队列?一个完整的 VoIP 平台?或者是实施数据包筛选器、转换、检查器或协议转码器?

Workers 十分强大,绝不仅仅限于 HTTP 和 WebSockets,因此我们很快将引入 Socket Workers——也就是说,可以使用原始 TCP、UDP 或 QUIC 协议直接连接到 Workers,而无需使用 HTTP。

这种新的 Workers 功能会是什么样?许多细节仍在进行开发,但想法是部署一个 Worker 脚本,采用与如今“fetch”事件差不多的运作方式了解和响应“connect”事件。重要的是,这将建立在开发用于客户端连接的相同通用套接字 API 上:

addEventListener('connect', (event) => {
  const enc = new TextEncoder();
  const writer = event.socket.writable.getWriter();
  writer.write(enc.encode('Hello World'));
  writer.close();
});

后续步骤(以及行动呼吁)

用于 JavaScript 和 Socket Workers 的新套接字 API 正在积极开发中,最初的重点是提供更好更有效的方法让 Workers 连接到后端的数据库。您可以在此处注册以加入访问 Database Connectors 和 Socket Workers 的等待名单。我们很期待与早期用户以及我们的技术合作伙伴合作,以开发、优化和测试这些新功能。

一旦发布后,我们希望 Socket Workers 能够为可部署到 Cloudflare 网络边缘的智能分布式应用程序类型敞开大门,很期待看到大家使用这些功能构建应用程序的成果。

我们保护 整个企业网络, 帮助客户高效构建 互联网规模应用, 加速一切 网站或互联网应用 , 抵御 DDoS 攻击, 阻止 黑客, 并可帮助您踏上 Zero Trust 之旅

从任何设备访问 1.1.1.1, 使用我们的免费应用加速和保护您的互联网。

如需进一步了解我们帮助构建更美好互联网的使命,请从 这里 开始。如果您正在寻找新的职业方向,请查看 我们的空缺职位

Full Stack Week (CN) TCP (CN) Cloudflare Workers (CN) QUIC (CN) 简体中文 (CN)

Follow on Twitter

Brendan Coll |@_mrbbot
Jonathan Kuperman |@jkup
Cloudflare |Cloudflare

Related Posts

December 19, 2021 1:59PM

在 Cloudflare 上构建您的下一个视频应用程序

过去,构建视频应用程序十分困难。在录制、编码和播放视频背后有许多复杂的技术。幸运的是,Cloudflare Stream 分担走了所有困难的部分,现在您可以轻松构建自定义视频和流媒体应用程序。让我们看一下,我们可以如何结合 Cloudflare Stream、Access、Pages 和 Workers,使用极少的代码创建一个高性能的视频应用程序。...

November 17, 2021 3:03PM

Cloudflare Pages 现已提供对 GitLab 的支持

在我们对 Pages 形成概念的早期阶段,我们着手构建能够与现有工作流程无缝集成的平台,为开发人员提供顺畅体验。但是,在宣布 Pages 正式发布后,我们意识到这个平台可能实际上无法由每个开发人员使用。今天之前,只有将 GitHub 用作源代码管理工具的开发人员才能享有 Pages 体验。...