适用于 Delphi 和 C++ Builder 的 QUIC 客户端与服务器组件 | eSeGeCe 博客

适用于 Delphi 和 C++ Builder 的 QUIC 客户端与服务器组件

· 组件
sgcQUIC QUIC 客户端与服务器组件

sgcQUICQUIC 传输协议(RFC 9000)带到 Delphi、C++ Builder 和 .NET。它提供两个新组件 TsgcQUICClientTsgcQUICServer,二者均基于 OpenSSL 3.5 中的原生 QUIC 引擎构建,因此传输与 TLS 1.3 握手作为单次往返一起运行。

QUIC 是 HTTP/3 底层的协议,但它本身也很有用。它运行在 UDP 之上,在一条连接上多路复用许多独立的流,通过 0-RTT 恢复,并借助连接迁移在网络切换后依然存活。本文介绍原始的 QUIC 层。下一篇文章将介绍在其之上运行的 HTTP/3 组件。

为什么选择 QUIC

经典的 TLS-over-TCP 连接在传输第一个字节的应用数据之前,需要先完成 TCP 握手,然后再完成 TLS 握手。QUIC 将两者合并为一次交换,因此一条全新连接在单次往返内即可就绪,而已恢复的连接可以通过 0-RTT 发送数据。

由于每条 QUIC 流都独立交付,一条流上丢失的数据包不会阻塞其他流。这消除了在单个 TCP 套接字上多路复用时会遇到的队头阻塞。QUIC 连接由连接 ID 标识,而不是由 IP 和端口对标识,因此它可以从 Wi-Fi 迁移到移动数据而不中断。

QUIC 客户端

设置 HostPort,分配事件,然后将 Active 设为 True。握手在单次往返内完成,而 WriteData 在 QUIC 流上发送字节。

uses
  sgcQUIC_Client;

var
  oClient: TsgcQUICClient;
begin
  oClient := TsgcQUICClient.Create(nil);
  oClient.Host := 'www.example.com';
  oClient.Port := 443;
  oClient.OnQUICConnect    := OnQUICConnect;
  oClient.OnQUICStreamData := OnQUICStreamData;
  oClient.OnQUICDisconnect := OnQUICDisconnect;

  oClient.Active := True;          // TLS 1.3 handshake in a single flight
  oClient.WriteData('ping');       // send bytes on a QUIC stream
end;

入站字节到达 OnQUICStreamData 事件,该事件报告流 id 和有效载荷:

procedure TForm1.OnQUICStreamData(Sender: TObject; aStreamId: Int64;
  aUnidirectional: Boolean; const aData: TBytes);
begin
  Memo1.Lines.Add('stream ' + IntToStr(aStreamId) + ': ' +
    TEncoding.UTF8.GetString(aData));
end;

QUIC 服务器

服务器在 UDP 端口上侦听,并需要一份 PEM 格式的证书和私钥。QUIC 始终运行在 TLS 1.3 之上,因此证书是必需的。客户端字节到达 OnQUICData,你通过 WriteData 回复,并传入你想要应答的连接。

uses
  sgcQUIC_Server;

var
  oServer: TsgcQUICServer;
begin
  oServer := TsgcQUICServer.Create(nil);
  oServer.Port := 443;
  oServer.QUICOptions.SSLOptions.CertFile := 'cert.pem';
  oServer.QUICOptions.SSLOptions.KeyFile  := 'key.pem';
  oServer.OnQUICConnect := OnQUICConnect;
  oServer.OnQUICData    := OnQUICData;
  oServer.Active := True;
end;

procedure TForm1.OnQUICData(Sender: TObject;
  aConnection: TsgcQUICServerConnection; const aData: TBytes);
begin
  // echo the message back to the client that sent it
  oServer.WriteData(aConnection, aData);
end;

多路复用流

一条 QUIC 连接可以同时承载许多流。在连接之前调用 EnableMultiStream,然后按需打开任意数量的流。双向流承载一个请求及其回复;单向流则单向推送数据。

oClient.EnableMultiStream;
oClient.OpenStream;                 // a new bidirectional stream
oClient.OpenStream(True);           // a unidirectional stream

多流模式使用内置的 OpenSSL 3.5 QUIC 引擎。每条流都独立进行流量控制,因此缓慢或停滞的流永远不会阻塞其余的流。

0-RTT 与连接迁移

在首次握手成功之后,客户端可以保留会话票据并使用 0-RTT 重新连接,在第一个数据包中就发送应用数据。连接迁移使会话在网络切换后依然保持活跃,这对于在 Wi-Fi 和蜂窝网络之间移动的移动客户端很重要。二者均由底层的 QUIC 引擎处理。

可用性

sgcQUIC 是一个独立的软件包,作为 sgcWebSockets Enterprise 的附加组件授权。每份许可证都包含完整的 Pascal 源代码和一年的更新。这些组件安装在 SGC QUIC 面板上,支持 Delphi 和 C++ Builder 7 到 13,以及具有相同 Tsgc 类名的 .NET 移植版本。

HTTP/3 客户端和服务器组件在下一篇文章中介绍。你可以下载试用版,并在 sgcQUIC 产品页面上阅读完整的组件参考。

有问题或反馈?联系我们,你会收到编写这些代码的人的回复。