JS `WebTransport` (HTTP/3 over UDP):下一代实时通信协议

各位观众,各位朋友,大家好!我是今天的主讲人,咱们今天聊聊这个听起来有点科幻,但其实离我们已经不远的 WebTransport。别被它那个“HTTP/3 over UDP”的头衔吓着,其实它就是个更快的、更灵活的“网页版实时通信管道”。

WebTransport:告别 WebSocket,拥抱 UDP 的未来

你可能听说过 WebSocket,它让网页能和服务器建立一个长连接,实现实时通信。但是,WebSocket 毕竟还是基于 TCP 的,TCP 有队头阻塞问题(Head-of-Line Blocking),一旦前面的数据包丢了,后面的数据包也得跟着等着,这在实时性要求高的场景下可不行。

WebTransport 呢,它直接基于 UDP,UDP 可是个“我发送,我快乐,丢了就丢了”的协议。当然,直接用 UDP 肯定不行,得加点东西保证可靠性。WebTransport 用的是 HTTP/3 的 QUIC 协议,QUIC 在 UDP 的基础上实现了可靠传输、拥塞控制、多路复用等功能,还自带加密,简直是 UDP 的“豪华升级版”。

WebTransport 的优势:

  • 低延迟: 基于 UDP,避免了 TCP 的队头阻塞,延迟更低。
  • 多路复用: 可以在一个连接上建立多个独立的流,互不影响。
  • 可靠性与不可靠性并存: 既可以发送可靠的数据,也可以发送不可靠的数据,满足不同场景的需求。
  • 双向通信: 客户端和服务器可以随时互相发送数据。
  • 支持连接迁移: 即使客户端的网络发生变化,连接也能保持,不会中断。

WebTransport 的应用场景:

  • 在线游戏: 实时同步游戏状态,延迟是关键。
  • 实时音视频: 视频会议、直播,需要低延迟和高带宽。
  • 远程控制: 远程桌面、远程调试,需要快速响应。
  • 数据推送: 服务器主动向客户端推送数据,例如实时股票行情。

WebTransport 的核心概念:

  • WebTransport: 整个连接对象,负责建立和管理连接。
  • Streams(流): 在 WebTransport 连接上建立的单向或双向数据通道。分为:
    • Unidirectional Streams(单向流): 只能由一方发送数据,另一方接收数据。
    • Bidirectional Streams(双向流): 双方都可以发送和接收数据。
  • Datagrams(数据报): 无需建立流,直接发送的 UDP 数据包,不可靠。

WebTransport 的代码示例:

咱们来点干货,看看 WebTransport 的代码怎么写。

服务器端 (Node.js):

首先,你需要一个支持 HTTP/3 的服务器。这里我们用 node-webtransport 这个库。

const {
  WebTransportServer,
  WebTransport,
  WebTransportSession,
  WebTransportDatagramWriter,
  WebTransportStream,
} = require('node-webtransport');
const fs = require('fs');

const key = fs.readFileSync('localhost.key');
const cert = fs.readFileSync('localhost.crt');

const server = new WebTransportServer({
  port: 4433,
  serverOptions: {
    key,
    cert,
  }
});

server.listen();

server.on('session', (session) => {
  console.log('New session');

  session.on('stream', async (stream) => {
    console.log('New stream');

    // 读取客户端发送的数据
    const reader = stream.readable.getReader();
    try {
      while (true) {
        const { done, value } = await reader.read();
        if (done) {
          break;
        }
        console.log('Received:', new TextDecoder().decode(value));

        // 将数据返回给客户端
        const writer = stream.writable.getWriter();
        await writer.write(value);
        await writer.close();
      }
    } catch (e) {
      console.error(e);
    } finally {
      reader.releaseLock();
    }
  });

  session.datagrams.readable.pipeTo(new WritableStream({
      write(chunk) {
          console.log("Datagram received:", new TextDecoder().decode(chunk));
      }
  }))
});

console.log('WebTransport server listening on port 4433');

这段代码创建了一个 WebTransport 服务器,监听在 4433 端口。当有新的客户端连接时,会触发 session 事件。当客户端创建新的流时,会触发 stream 事件。服务器会读取客户端发送的数据,并将其返回给客户端。同时监听datagrams,接收客户端发来的不可靠数据。

客户端 (JavaScript):

async function connectWebTransport() {
  try {
    const wt = new WebTransport("https://localhost:4433/"); // 替换为你的服务器地址

    await wt.ready;
    console.log("Connected to WebTransport server!");

    // 创建一个双向流
    const stream = await wt.createBidirectionalStream();
    console.log("Created bidirectional stream");

    // 向服务器发送数据
    const writer = stream.writable.getWriter();
    await writer.write(new TextEncoder().encode("Hello from the client!"));
    await writer.close();
    console.log("Sent data to server");

    // 读取服务器返回的数据
    const reader = stream.readable.getReader();
    const { value, done } = await reader.read();
    reader.releaseLock();

    if (done) {
        console.log("Stream closed by server");
    } else {
      console.log("Received from server:", new TextDecoder().decode(value));
    }

    //发送datagram
    const datagramWriter = wt.datagrams.writable.getWriter();
    await datagramWriter.write(new TextEncoder().encode("Hello Datagram!"));
    await datagramWriter.close();

    // 关闭连接
    await wt.close();
    console.log("WebTransport connection closed");

  } catch (e) {
    console.error("WebTransport connection failed:", e);
  }
}

connectWebTransport();

这段代码连接到 WebTransport 服务器,创建一个双向流,向服务器发送数据,并读取服务器返回的数据。最后发送一个datagram,并关闭连接。

注意事项:

  • HTTPS: WebTransport 必须使用 HTTPS,因为 QUIC 需要加密。
  • 证书: 你需要生成一个自签名证书,或者使用有效的 SSL 证书。
  • 浏览器支持: 目前 WebTransport 还在实验阶段,需要启用浏览器的实验性功能。例如,在 Chrome 中,你需要启用 chrome://flags/#enable-experimental-web-platform-features
  • node-webtransport: 这个库目前还在积极开发中,API 可能会发生变化。

Unidirectional Streams (单向流) 和 Bidirectional Streams (双向流) 的比较:

特性 Unidirectional Stream Bidirectional Stream
方向 单向 (只能由一方发送,另一方接收) 双向 (双方都可以发送和接收)
创建者 可以由客户端或服务器创建 可以由客户端或服务器创建
用途 适用于单向数据传输,例如服务器推送数据、客户端上传文件 适用于双向交互,例如客户端发送请求,服务器返回响应
代码示例 (客户端) wt.createUnidirectionalStream() wt.createBidirectionalStream()

Datagrams (数据报) 的使用:

Datagrams 是一种不可靠的传输方式,适用于对延迟非常敏感,但对数据丢失不敏感的场景。例如,在在线游戏中,可以用来发送玩家的位置信息。

// 发送 Datagram (客户端)
const datagramWriter = wt.datagrams.writable.getWriter();
await datagramWriter.write(new TextEncoder().encode("Player position: x=10, y=20"));
await datagramWriter.close();

// 接收 Datagram (服务器端)
session.datagrams.readable.pipeTo(new WritableStream({
    write(chunk) {
        console.log("Datagram received:", new TextDecoder().decode(chunk));
    }
}))

WebTransport 的未来:

WebTransport 还在发展中,但它代表了 Web 实时通信的未来。随着浏览器和服务器的支持越来越完善,WebTransport 将会在更多的场景中得到应用。

一些有用的资源:

总结:

WebTransport 是一个令人兴奋的新技术,它为 Web 实时通信带来了更高的性能和更大的灵活性。虽然目前还在实验阶段,但它已经展现出了巨大的潜力。如果你对实时通信感兴趣,不妨关注一下 WebTransport,也许它会给你带来惊喜。

Q & A:

好了,今天的讲座就到这里。大家有什么问题吗? 欢迎提问!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注