sgcWebSockets 2026.5 是一次内容丰富的版本发布。三个新的基础设施组件将 WebSocket / HTTP 服务器升级为生产级 API 网关:一个功能齐全的速率限制器、一个客户端熔断器,以及一个支持完整生命周期的 API 密钥管理器。在协议层面,新增了构建于通用 Lightstreamer TLCP 2.5 实现之上的 Forex.com 客户端,MCP Server 内置了 OAuth 2.1 流程,可直接对接如 claude.ai 等基于浏览器的 MCP 客户端;IOCP(Windows)与 EPOLL(Linux)I/O 引擎获得了六项可衡量的性能提升。还包含了一个早期的后量子原语:sgcKEM_CreateMLKEM768Keys,用于生成 ML-KEM-768 密钥对。
本文将通过可直接粘贴使用的 Delphi 代码片段,依次介绍这些亮点。
TsgcWSRateLimiter — 开箱即用的 API 速率限制
在服务器旁放置一个 TsgcWSRateLimiter,便可获得基于令牌桶、滑动窗口或固定窗口的速率限制,支持按 IP、按 API 密钥、按用户或按端点模式进行限制,外加按日/按月配额和突发保护。该组件是线程安全的,并将状态持久化到磁盘(这样服务器重启后不会让每个客户端获得全新的额度)。
uses
sgcWebSocket_Server_RateLimiter;
var
oRL: TsgcWSRateLimiter;
oResult: TsgcRateLimitResult;
begin
oRL := TsgcWSRateLimiter.Create(nil);
try
oRL.TokenBucket.Enabled := True;
oRL.TokenBucket.Capacity := 100; // burst size
oRL.TokenBucket.RefillRate := 10; // tokens / interval
oRL.TokenBucket.RefillIntervalMs := 1000;
oRL.PerIP.Enabled := True;
oRL.PerIP.MaxRequests := 60;
oRL.PerIP.WindowSec := 60;
// Consume one token for the current request
oResult := oRL.Consume('ip:' + vClientIP);
if not oResult.Allowed then
RespondHTTP(429, 'Retry-After: ' + IntToStr(oResult.RetryAfterSec));
finally
oRL.Free;
end;
end;
规则解析器会依次遍历 PerEndpoint(支持通配符匹配)、PerAPIKey、PerUser,最后是 PerIP。OnThrottled、OnQuotaExceeded 和 OnStateChange 事件可让您记录或覆盖每一个判定。
演示:Demos\04.WebSocket_Other_Samples\14.RateLimiter — 一个洪流式生成请求的客户端,对应一台发布实时统计和拒绝原因的服务器。
TsgcWSCircuitBreaker — 客户端故障隔离
当上游 API(api.openai.com、支付网关或内部微服务)开始失败或变慢时,挂在 TCP 超时上会耗费连接、线程和资金。TsgcWSCircuitBreaker 在任意 TsgcHTTPAPI_client 子类之上实现了经典的三态模式(关闭 / 打开 / 半开),具备滚动时间窗口、慢调用检测、可选的回退响应以及按端点的覆盖配置。
uses
sgcWebSocket_CircuitBreaker;
var
oCB: TsgcWSCircuitBreaker;
begin
oCB := TsgcWSCircuitBreaker.Create(nil);
try
oCB.Thresholds.FailureCount := 5;
oCB.Thresholds.FailureRatePercent := 50;
oCB.Thresholds.SlowCallDurationMs := 2000;
oCB.Thresholds.SlowCallRatePercent := 80;
oCB.TimeWindow.RollingWindowSec := 60;
oCB.Recovery.CooldownSec := 30;
oCB.Recovery.HalfOpenTrialCalls := 3;
oCB.Fallback.Enabled := True;
oCB.Fallback.UseLastSuccess := True;
if oCB.IsCallAllowed('openai') then
try
vResponse := oOpenAI.ChatCompletion(...);
oCB.RecordSuccess('openai');
except
on E: Exception do
begin
oCB.RecordFailure('openai', E.ClassName);
raise;
end;
end
else
vResponse := 'service temporarily unavailable';
finally
oCB.Free;
end;
end;
在 Delphi 2009+ 上还提供了一个单行封装:oCB.Execute('openai', procedure begin oOpenAI.ChatCompletion(...) end); — 成功 / 失败的记录会自动完成。
演示:Demos\04.WebSocket_Other_Samples\15.CircuitBreaker。
TsgcWSAPIKeyManager — 单组件管理密钥生命周期
大多数 "WebSocket API" 服务器都需要 API 密钥:签发、校验、撤销、轮换。TsgcWSAPIKeyManager 封装了完整的生命周期,包括基于作用域的授权、可选的静态哈希、过期、审计日志,以及内置的轮换宽限期,使旧密钥在轮换后于可配置的时间窗口内继续有效。
uses
sgcWebSocket_Server_APIKeyManager;
var
oKM: TsgcWSAPIKeyManager;
vKey, vNewKey: string;
begin
oKM := TsgcWSAPIKeyManager.Create(nil);
try
oKM.Generation.Length := 40;
oKM.Generation.Prefix := 'sgc_';
oKM.Hashing.Enabled := True; // store SHA-256 hash, not the plaintext
oKM.Rotation.GracePeriodSec := 86400; // old key valid for 24h after rotation
oKM.Expiration.DefaultTTLSec := 30 * 86400;
// Issue a key for tenant "acme" with read+write scopes, expiring in 7 days
vKey := oKM.IssueKey('acme', ['read', 'write'], 7 * 86400);
// Validate the key on each request, optionally requiring a scope
if not oKM.ValidateKey(vKey, 'read', vClientIP) then
RespondHTTP(401, 'invalid api key');
// Rotate a key (returns the new plaintext; old key remains valid for GracePeriodSec)
oKM.RotateKey(vKey, vNewKey);
finally
oKM.Free;
end;
end;
该组件可以通过 IsRequestAuthorized 直接从入站 HTTP 头或查询字符串中读取密钥,因此您无需自行编写提取逻辑。
演示:Demos\04.WebSocket_Other_Samples\16.APIKeyManager。
Forex.com 客户端 + 通用 Lightstreamer
新的 TsgcWSAPI_Forex 客户端提供了对 Forex.com 的统一 REST + 流式访问(登录、心跳、行情监视、持仓、订单、交易历史、模拟交易)。它构建于全新的 TsgcWSPClient_Lightstreamer 组件之上:这是一个通用的 Lightstreamer TLCP 2.5 客户端,实现了 create_session、bind_session、control(订阅 / 取消订阅)以及 LOOP 自动重新绑定 + 重连后订阅重放。该 Lightstreamer 客户端本身可以独立复用,相同的代码基础同样适用于 IG Markets 以及任何基于 Lightstreamer 的行情源。
uses sgcHTTP_API_Forex;
var oFX: TsgcWSAPI_Forex;
begin
oFX := TsgcWSAPI_Forex.Create(nil);
oFX.UserName := 'demo-user';
oFX.Password := 'secret';
oFX.AppKey := 'your-app-key';
oFX.Login;
oFX.SubscribePrices(['EUR/USD', 'GBP/USD', 'XAU/USD']);
oFX.OnPriceUpdate := procedure(const aSymbol: string; aBid, aAsk: Double)
begin
ShowMessage(Format('%s %.5f / %.5f', [aSymbol, aBid, aAsk]));
end;
end;
完整的 GUI 演示位于 Demos\05.Crypto\22.Forex — 包含登录、连通性心跳、实时行情监视、持仓、活动订单、交易历史、止损 / 限价历史以及模拟交易,凭据会被持久化到 sgcForexDemo.ini。
MCP Server — 面向浏览器 MCP 客户端的 OAuth 2.1
MCP Server 现在可以直接与基于浏览器的 MCP 连接器(例如 claude.ai)通信,无需外部授权服务器。它会自动发布 MCP 浏览器连接器规范所要求的四个 OAuth 发现 / 注册端点,运行带有 HTML 同意页面的 PKCE-S256 授权流程,并签发刷新令牌:
GET /.well-known/oauth-authorization-server— RFC 8414 元数据。GET /.well-known/oauth-protected-resource— RFC 9728 受保护资源元数据。POST /oauth/register— RFC 7591 动态客户端注册。GET /oauth/authorize— HTML 同意表单。POST /oauth/token— PKCE S256 + 刷新令牌。
CORS 在内联中处理:OPTIONS 预检在身份验证之前返回 204,并附带完整的 Access-Control-* 头;每个响应都会带有一个反射请求来源的 Access-Control-Allow-Origin 头,以及一个 Strict-Transport-Security: max-age=31536000 HSTS 头。
IOCP 和 EPOLL:六项调优收益
Windows IOCP 与 Linux EPOLL I/O 引擎获得了一轮聚焦于性能与可调优性的改进。
IOCP(Windows)
ThreadAffinity(默认False),位于TsgcIndy_IO_Engine— 通过SetThreadAffinityMask将引擎线程以轮转方式绑定到逻辑核心。可减少高核数系统上的跨核缓存流量。Metrics— 新增TsgcIndy_IO_EngineMetrics记录(AcceptsPosted、AcceptsCompleted、ReadsPosted、ReadsCompleted、ActiveConnections、BytesRead、BytesWritten),在临界区下更新。不必再猜测。SendBufferSize、ReceiveBufferSize、TCPNoDelay,位于TsgcIndy_IOHandler_IO_IOCP— 在AfterAccept中通过setsockopt应用,因此每连接调优不再需要自定义OnConnect处理器。TsgcPerIoDataPool容量从 256 提升到 2048,避免了高连接并发下回退到GetMem/FreeMem堆分配。在 loopback 基准下 WebSocket 吞吐量提升 +15–18%。
oServer.Bindings.Add.Port := 443;
oServer.IOHandler := TsgcIndy_IOHandler_IO_IOCP.Create(oServer);
with TsgcIndy_IOHandler_IO_IOCP(oServer.IOHandler) do
begin
SendBufferSize := 256 * 1024;
ReceiveBufferSize := 256 * 1024;
TCPNoDelay := True;
Engine.ThreadAffinity := True;
end;
EPOLL(Linux)
AcceptBatchSize、WaitTimeoutMS、HandshakeTimeoutMS— 调优 accept 循环和慢速 loris 防护。- 由 EPOLLOUT 驱动的写入背压 — 当
send()在部分写入时返回EAGAIN,剩余字节会被捕获到每连接的待发送缓冲区中,并使用EPOLLIN|EPOLLOUT重新装备套接字。反应器会在下一次EPOLLOUT事件中冲刷尾部数据,而不是丢弃字节或阻塞 worker。
共享
IOCP / EPOLL 的 worker 池过去会在每次迭代时都执行 sleep(1),包括刚刚处理完一个任务之后 — 实际上将每个 worker 限制在约 1,000 ops/s,即使队列已满也是如此。现在只要有等待中的工作,就会跳过该 sleep,这一上限随之消失。
HTTP.sys:可选的高性能模式
HTTP.sys 服务器新增了带 OperatingMode 选择器的 FineTune 属性。默认的 ompClassic 保留现有行为。新的 ompHighPerf 模式实现了 MSDN 推荐的 N-workers × M-pre-posted-async-receives 模式 — 即面向高吞吐 HTTP.sys 部署所推荐的架构 — 并将其封装在单个属性之下:
oServer := TsgcWebSocketHTTPServer.Create(nil);
oServer.HTTP2Options.SecureOptions.HTTPAPI := True; // use HTTP.sys
oServer.FineTune.OperatingMode := ompHighPerf;
oServer.FineTune.WorkerCount := 8;
oServer.FineTune.PrePostedReceivesPerWorker := 16;
oServer.Active := True;
THttpServerRequest 和 THttpServerResponse 也进行了扩展,新增了若干字段,涵盖此前只能通过手动解析获得的详细信息。
后量子原语:ML-KEM-768
一个小而具有前瞻性的新增:sgcKEM_CreateMLKEM768Keys 生成 ML-KEM-768(FIPS 203 / Kyber-768)密钥对,同时输出 PEM 和原始字节两种形式。ML-KEM 是 NIST 标准化的后量子 KEM,并在 IETF 路线图中用于混合 TLS 1.3(X25519MLKEM768)。这为在即将到来的 OpenSSL 3.5 / 3.6 基线之前实验 PQ 就绪握手扫清了障碍。
uses sgcKEM;
var vPubPEM, vPrivPEM: string; vPubRaw, vPrivRaw: TBytes;
begin
sgcKEM_CreateMLKEM768Keys(vPubPEM, vPrivPEM, vPubRaw, vPrivRaw);
TFile.WriteAllText('mlkem768_pub.pem', vPubPEM);
TFile.WriteAllText('mlkem768_priv.pem', vPrivPEM);
end;
可靠性与一致性修复
本次 bug 修复批次解决了一长串 MCP、HTTP.sys、IOCP 和 HTTP/2 的问题。要点如下:
- MCP Server — 缺失或无效的凭据现在会返回
401 Unauthorized,并附带指向受保护资源元数据的WWW-Authenticate: Bearer头,而不是500 Internal Server Error。这是基于浏览器的 MCP 客户端进行 OAuth 发现所必需的。 - MCP Server —
OPTIONS请求不再进入 JSON-RPC 解析器(此前会返回500 "Invalid jsonrpc Value")。CORS 预检现在在身份验证之前、MCP 主体解析器之前处理。 - MCP Server — 包含非 ASCII 字符的工具描述、提示消息和资源内容不再会中断连接(JSON 主体现在与声明的
charset=utf-8一致)。 - MCP Server —
tool/prompt/resource/root/template/ completion-ref 和 completion-argument 的name字段中包含的非 ASCII 字符,现在会正确地以 JSON\uXXXX转义形式发送和读取,而不是原始的 UTF-16 码点。 - HTTP API 请求体 —
TsgcWSComponent_Server.DoHTTPRequestAPI此前调用ReadStringFromStream时未指定编码,默认为 ASCII,在事件处理器看到之前就把每个非 ASCII 字节替换为?。已修复。 - HTTP.sys Server —
TsgcHTTPServerAPI.DoExecute中ERROR_MORE_DATA上的上下文泄漏。accept 循环现在会扩大缓冲区并在同一 request id 上重试HttpReceiveHttpRequest,并在所有错误路径上释放孤立的上下文。 - HTTP.sys Server —
TsgcWSConnectionServer_HTTPAPI.DoSendHTTP_Response不再在最终响应上设置HTTP_SEND_RESPONSE_FLAG_MORE_DATA。 - IOCP IOHandler —
TsgcIndy_IO_Engine_IOCP_Base.DoStopThreads此前在DWORD线程 ID 数组(FThreadsId)上调用WaitForMultipleObjects,而不是线程句柄。已修复。 - IOCP IOHandler — 套接字上挂起的 I/O 操作现在会在关闭时以及每个套接字关闭时取消。
- IOCP IOHandler —
DoFreePerIoData中脆弱的Overlapped.Internal = STATUS_PENDING探测,已被TsgcPerIoData上一个显式的Completed: Boolean标志所替代。 - HTTP/2 WebBrokerBridge — 当 DataSnap REST 处理仅含 HTTP/2
HEADERS帧的请求时,TsgcWSHTTPServer.OnHTTP2RequestEvent中sgcFree(oResponse)出现的无效指针操作。
升级
对于现有的 2026.4 项目,2026.5 是一次开箱即用的升级。未对现有组件进行任何接口变更;新的速率限制 / 熔断器 / API 密钥组件是附加且可选启用的。HTTP.sys 高性能模式被门控在 FineTune.OperatingMode := ompHighPerf 之后 — 现有代码保持在经典路径上。
拥有有效订阅的客户可从客户专区下载新版本。试用用户可在 esegece.com/products/sgcwebsockets/sgcwebsockets-download 获取更新后的安装程序。
有问题、反馈或需要迁移帮助?联系我们 — 您会收到代码作者本人的回复。
