首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >一个新的跨 JavaScript 运行时的 Socket API!

一个新的跨 JavaScript 运行时的 Socket API!

作者头像
ConardLi
发布2023-10-09 12:52:21
发布2023-10-09 12:52:21
4470
举报
文章被收录于专栏:code秘密花园code秘密花园

大家好,我是 ConardLi

今天和大家来一起聊一个即将推出的跨 JavaScript 运行时的 Socket API 。

什么是 TCP 套接字

TCP(传输控制协议)是互联网的基础网络协议。它是用于发出 HTTP 请求(在 HTTP/3 之前,使用 QUIC )、通过 SMTP 发送电子邮件、使用数据库特定协议(如 MySQL )和许多其他应用程序层协议查询数据库的底层协议。

TCP Scoket 是一种编程接口,代表两个都同意通过 TCP “通话”的应用程序之间的双向通信连接。一个应用程序启动与正在侦听入站 TCP 连接的另一个应用程序的出站 TCP 连接。通过协商三次握手建立连接,握手完成后就可以双向发送数据。

Scoket 是单个 TCP 连接的编程接口 - 它有一个可读和可写的数据 "流",只要连接保持打开,应用程序就可以持续读写数据。

Socket 兼容性

对于 Workers,我们的目标是尽可能支持跨浏览器和非浏览器环境支持的标准 API,以便尽可能多的 NPM 包无需更改即可在 Workers 上运行,并且包作者不必编写特定于运行时的代码。

但对于 TCP Scoket,迄今为止,JavaScript 运行时还没有用于创建和使用 TCPUDP Scoket 的标准 API

Node.js 提供了 nettls API,但这些 API 是在 10 多年前 Node.js 项目的早期设计的,并且仍然基于回调。使用起来太麻烦了,并且它们也不适合 Serverless 平台或 Web 浏览器的方式公开配置。

代码语言:javascript
复制
var server = net.createServer(); 

server.listen(9000, () => { 
  console.log('opened server on port: ', 9000); 
}); 

server.on("connection", (socket) => { 
  console.log("new client connection is made"); 
}); 

另外 Deno 也实现了一套不同的 API — Deno.connect

代码语言:javascript
复制
const conn1 = await Deno.connect({ port: 80 });
const conn2 = await Deno.connect({ hostname: "192.0.2.1", port: 80 });
const conn3 = await Deno.connect({ hostname: "[2001:db8::1]", port: 80 });
const conn4 = await Deno.connect({ hostname: "golang.org", port: 80, transport: "tcp" });

尽管 WICG 提案确实也是存在的,但 Web 浏览器不提供原始 TCP 套接字 API ,并且它与 Node.jsDeno 也都不同。

connect() — 一个通用的 Socket API

基于这样的背景,CloudflareVercel 的工程师发布了一套通用的 Socket API 规范:

Sockets API 的草案规范定义了以下 API

代码语言:javascript
复制
dictionary SocketAddress {
  DOMString hostname;
  unsigned short port;
};

typedef (DOMString or SocketAddress) AnySocketAddress;

enum SecureTransportKind { "off", "on", "starttls" };

[Exposed=*]
dictionary SocketOptions {
  SecureTransportKind secureTransport = "off";
  boolean allowHalfOpen = false;
};

[Exposed=*]
interface Connect {
  Socket connect(AnySocketAddress address, optional SocketOptions opts);
};

interface Socket {
  readonly attribute ReadableStream readable;
  readonly attribute WritableStream writable;

  readonly attribute Promise<undefined> closed;
  Promise<undefined> close();

  Socket startTls();
};

提案的 API 是基于 Promise 的,并尽可能的复用了现有的标准。例如 ReadableStreamWritableStream 用于 socket 的读写端。这使得我们可以很轻松地将数据从 TCP Socket 传输到接受 ReadableStream 作为输入的任何其他库或现有代码,或者通过 WritableStream 写入 TCP Socket

API 的入口点是 connect() 函数,它接受一个包含主机名和端口(以冒号分隔)的字符串,或者一个具有离散主机名和端口字段的对象。它返回一个代表套接字连接的 Socket 对象。该对象的实例公开用于处理连接的属性和方法。

通过调用 Socket 对象上的 startTls() 方法,我们可以在纯文本或 TLS 模式下建立连接,也可以在特殊的 "starttls" 模式下建立连接,该模式允许 Socket 在进行一段时间的纯文本数据传输后轻松升级为 TLS。一旦 Socket 升级为使用 TLS,就无需创建新的 Socket ,也无需转而使用一套单独的应用程序接口。

下面是个简单的例子:

代码语言:javascript
复制
import { connect } from "@arrowood.dev/socket"

const options = { secureTransport: "starttls" };
const socket = connect("address:port", options);
const secureSocket = socket.startTls();

// The socket is immediately writable
// Relies on web standard WritableStream
const writer = secureSocket.writable.getWriter();
const encoder = new TextEncoder();
const encoded = encoder.encode("hello");
await writer.write(encoded);

下面是使用 node:netnode:tls API 的等效代码:

代码语言:javascript
复制
import tls from 'node:tls'

const socket = new net.Socket(HOST, PORT);
socket.once('connect', () => {
  const options = { socket };
  const secureSocket = tls.connect(options, () => {
    // The socket can only be written to once the
    // connection is established.
    // Polymorphic API, uses Node.js streams
    secureSocket.write('hello');
  }
})

在库中使用 connect()Node.js 实现

为了让开源库维护者更容易采用 connect() API,目前在 Node.js 中也发布了 connect() 的实现,这样我们可以让库在不同的 JavaScript 运行时工作,而无需维护任何特定于运行时的代码。

代码语言:javascript
复制
npm install --save @arrowood.dev/socket

import { connect } from "@arrowood.dev/socket"

目前 Wintercg/proposal-sockets-api 将作为规范草案进行发布,再经过一段时间的反馈,这个 API 将在不久的将来成为 Node.js 的内置 API

最后

参考:

  • https://github.com/Ethan-Arrowood/socket
  • https://github.com/WICG/direct-sockets/blob/main/docs/explainer.md
  • https://blog.cloudflare.com/workers-tcp-socket-api-connect-databases/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 code秘密花园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是 TCP 套接字
  • Socket 兼容性
  • connect() — 一个通用的 Socket API
  • 在库中使用 connect() 的 Node.js 实现
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档