sgcWebSockets 2026.8은 올해 가장 큰 릴리스입니다. 새로운 전송 컴포넌트가 네 개 추가되어 클라이언트와 서버 양쪽에서 QUIC와 HTTP/3를 사용할 수 있고, 이제 OpenSSL을 실행 파일 안에 링크할 수 있어 TLS 애플리케이션을 DLL 하나 없이 배포할 수 있으며, sgcHTML은 서른 개가 넘는 컴포넌트가 늘어나고 WebBroker와 DataSnap 디스패처를 갖추었으며 휴대폰 화면에 맞춰 적응합니다.
내부적으로는 SChannel TLS 계층을 해체하고 다시 만들었습니다. Windows TLS 스택을 사용하신다면 이번이 꼭 설치해야 할 릴리스입니다. TLSOptions.Version이 아무 말 없이 무시되었고, 폐기된 인증서가 그대로 수락되었으며, TLS 1.3 연결은 끝내 완료되지 않았고, 재협상은 아무런 검사 없이 인증서를 교체했습니다. 이 모든 것이 수정되었고, 폐기 확인과 버전 하한선, 서버 측 클라이언트 인증서 검증을 이제 사용할 수 있습니다. 이 글의 나머지는 안내 투어이며, 각 섹션에서 해당 기능을 깊이 다루는 글로 연결됩니다.
QUIC와 HTTP/3
네 개의 새 컴포넌트가 QUIC(RFC 9000)와 HTTP/3(RFC 9114)를 Delphi와 C++ Builder로 가져옵니다. TsgcQUICClient, TsgcQUICServer, TsgcHTTP3Client, TsgcHTTP3Server입니다. 네이티브 OpenSSL 3.5 QUIC 엔진 위에서 동작하므로 배포해야 할 서드파티 스택이 없고, 핸드셰이크에 통합된 TLS 1.3, 헤드 오브 라인 블로킹이 없는 멀티플렉스 스트림, 0-RTT 재개, 그리고 클라이언트가 네트워크를 바꿀 때의 연결 마이그레이션을 얻습니다.
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.Active := True; // TLS 1.3 handshake in a single flight
oClient.WriteData('ping'); // send bytes on a QUIC stream
end;
HTTP/3 클라이언트는 모든 HTTP 메서드를 지원하고, QPACK 헤더 압축을 수행하며, 블로킹 또는 비동기 방식으로 동작하고, Alt-Svc를 통해 HTTP/3 엔드포인트를 발견하며, 서버 푸시를 처리합니다.
uses
sgcHTTP3_Client;
var
oClient: TsgcHTTP3Client;
vBody: string;
begin
oClient := TsgcHTTP3Client.Create(nil);
oClient.OnResponse := OnResponse;
oClient.OnAltSvc := OnAltSvc;
oClient.Connect('www.example.com', 443);
vBody := oClient.Get('https://www.example.com/');
end;
둘 다 sgcWebSockets Enterprise와 함께 sgcQUIC 패키지가 필요합니다. 자세히 보기: QUIC 클라이언트 및 서버 컴포넌트와 HTTP/3 클라이언트 및 서버 컴포넌트.
실행 파일 안의 OpenSSL
libcrypto와 libssl을 애플리케이션 옆에 함께 배포하는 일은 TLS 클라이언트를 출시할 때 언제나 가장 달갑지 않은 부분이었습니다. 2026.8부터 라이브러리는 OpenSSL 3.5.7을 정적으로 링크할 수 있습니다. 프로젝트의 uses 절에 유닛 하나를 추가하면 DLL이 사라집니다. 그 유닛을 제거하면 예전과 똑같이 다시 DLL을 로드하므로, 어느 방향이든 한 줄만 바꾸면 됩니다.
uses
sgcWebSocket, sgcWebSocket_Classes,
sgcIdSSLOpenSSL_Static;
클라이언트와 서버, 32비트와 64비트를 모두 지원하며 Delphi XE2 이상에서 사용할 수 있습니다. 자세히 보기: 정적 OpenSSL 링크, 이제 DLL은 필요 없습니다.
sgcHTML: WebBroker, DataSnap 그리고 서른 개의 새 컴포넌트
sgcHTML 페이지는 더 이상 sgcWebSockets 서버에 묶여 있지 않습니다. 새 디스패처 컴포넌트가 standalone, ISAPI, Apache, CGI 등 모든 WebBroker 애플리케이션에서, 그리고 DataSnap 서버에서 페이지를 제공합니다. DataSnap에서는 브리지가 REST 엔드포인트와 같은 포트로 실시간 WebSocket 업데이트를 더해 줍니다.
uses
Web.HTTPApp, sgcHTMX_Engine_Server_WebBroker, sgcHTMX_Router;
// Any WebBroker host: the engine's Owner is the web module,
// so the standard WebBroker dispatcher calls it automatically
FEngine := TsgcHTMX_Engine_Server_WebBroker.Create(WebModule1);
FEngine.Router := FRouter; // your htmx routes and the page
이번 릴리스에서 컴포넌트 세트가 크게 늘었고, 모든 것은 여전히 서버에서 그려지므로 로드할 클라이언트 측 라이브러리가 없습니다.
- 데이터. TreeGrid, PivotTable, ActivityFeed와 크기 조절이 가능한 Splitter, 여기에 Excel 내보내기, 각 행 아래의 상세 패널, 그리고 Grid에서 기억되는 열과 정렬 선택이 추가되었습니다. 자세히 보기: 구조화된 데이터를 위한 네 가지 새 sgcHTML 컴포넌트.
- 비주얼. Heatmap, Sparkline, CandlestickChart, TreeMap과 QRCode, Barcode가 추가되었고 모두 인라인 SVG로 렌더링됩니다. 자세히 보기: 여섯 가지 새 sgcHTML 비주얼.
- 폼. MultiSelect, ColorPicker, Slider, TimePicker, SignaturePad, Transfer가 추가되었고, 날짜 및 시간 선택기와 날짜 범위 선택기도 함께 제공됩니다. 자세히 보기: 여섯 가지 새 sgcHTML 폼 입력.
- 피드백. Badge, PDFViewer, ContextMenu, ProgressBar, JobProgress, LogViewer가 추가되었습니다. 자세히 보기: 여섯 가지 새 sgcHTML 피드백 컴포넌트.
- 관리. Presence, RolesPermissions, UserManagement가 추가되었습니다. 이들은 화면을 그리는 역할만 하며, 각 사용자가 무엇을 할 수 있는지는 여전히 여러분의 서버가 결정합니다. 자세히 보기: 세 가지 새 sgcHTML 관리 컴포넌트.
이제 페이지가 화면 크기에도 맞춰집니다. 휴대폰에서는 사이드 메뉴가 버튼 뒤로 접히고 콘텐츠가 전체 너비를 사용하며, 데스크톱에서는 아무것도 달라지지 않습니다. 예전의 고정 레이아웃을 원하면 새 Responsive 속성을 False로 설정하세요. 자세히 보기: WebBroker와 DataSnap에서의 sgcHTML.
SChannel TLS 전면 개편
SChannel은 Windows의 TLS 스택으로, OpenSSL을 전혀 배포하지 않아도 사용할 수 있는 스택입니다. 여기에는 바깥에서는 전혀 보이지 않는, 그래서 가장 나쁜 종류의 문제들이 있었습니다. Windows 11과 Windows Server 2022에서는 TLSOptions.Version을 아예 읽지 않았고, Windows 10에서 TLS 1.3을 요청하면 아무 말 없이 TLS 1.2가 사용되었으며, 버전을 지정하지 않으면 SSL 3.0, TLS 1.0, TLS 1.1이 다시 켜졌습니다. VerifyCertificate를 True로 설정해도 폐기된 서버 인증서가 수락되었는데, 체인을 만들 때 폐기 상태를 전혀 요청하지 않았기 때문입니다. 재협상 후에는 체인이나 호스트 이름을 확인하지 않고 새 인증서를 수락했습니다. Indy가 별도로 여는 연결, 예를 들어 다른 호스트로의 HTTP 리다이렉트나 FTP 데이터 채널은 빈 설정으로 돌아와 검증이 꺼진 상태로 동작했고, 그것을 알려 주는 것은 아무것도 없었습니다.
이 모든 것이 수정되었고, 이제 핸드셰이크가 완료될 때 협상된 버전을 확인하며, 이 작업과 함께 세 가지 새 옵션 그룹이 추가되었습니다. 폐기 확인, 버전 하한선, 그리고 Windows strong crypto입니다.
// client
oClient.TLSOptions.Version := tls1_3; // highest version to use
oClient.TLSOptions.SChannel_Options.VersionMin := tls1_2; // lowest accepted
oClient.TLSOptions.SChannel_Options.UseStrongCrypto := True;
oClient.TLSOptions.SChannel_Options.Revocation.Check := scrcChainExcludeRoot;
oClient.TLSOptions.SChannel_Options.Revocation.Timeout := 5000; // ms
// or all of it in one line
oClient.TLSOptions.Preset := tlspSecureDefaults;
폐기 확인의 기본값은 의도적으로 관대합니다. IgnoreRevocationOffline과 IgnoreNoRevocationCheck가 True이므로, 확인을 켠다고 해서 지금까지 잘 동작하던 연결이 끊기지 않습니다. 또 Timeout이 CRL과 OCSP 조회에 제한을 두어 응답하지 않는 응답기가 핸드셰이크를 멈춰 세울 수 없습니다. 실제로 폐기된 인증서는 언제나 거부됩니다.
서버 측에서는 이제 SChannel이 클라이언트에게 인증서를 요구할 수 있습니다. 이전에는 전혀 하지 못하던 일입니다. 클라이언트 인증서는 클라이언트가 서버 인증서에 적용하는 것과 같은 검사, 즉 체인과 유효 기간, OnSChannelVerifyPeer 이벤트를 거치며, 호스트 이름 검사만 제외됩니다.
oServer.SSLOptions.VerifyCertificate := True;
oServer.SSLOptions.VerifyCertificate_Options.FailIfNoCertificate := True;
여기에 두 가지 수정이 더 있습니다. SChannel을 사용하는 클라이언트는 프록시가 재시작할 때처럼 상대편이 종료 알림 없이 연결을 끊으면 연결이 사라진 것을 전혀 알아채지 못했고, 그래서 OnDisconnect가 발생하지 않고 WatchDog도 동작하지 않았습니다. 그리고 TLS 1.3 연결은 아예 완료되지 않았는데, 핸드셰이크 직후 서버가 보내는 세션 티켓 때문에 클라이언트가 서버가 이미 보낸 데이터를 계속 기다렸기 때문입니다. 이제 핸드셰이크는 TCP 연결 단계만 감싸는 대신 ConnectTimeout을 따르며, SChannel, Apple, Android 연결 모두에서 닫기 전에 종료 알림을 보냅니다.
서버 제한과 IOCP / EPOLL 엔진
서버에는 예전에 제한이 없던 항목들에 한도가 생겼습니다. WebSocket 서버는 이제 무제한 대신 기본적으로 동시 연결 10,000개를 수락하고, 클라이언트가 초당 보낼 수 있는 제어 프레임 수(100개)를 제한하여 핑으로 넘쳐나지 않도록 합니다. HTTP/2 서버에는 MaxRequestSize가, DTLS 컴포넌트에는 MaxConnections, HandshakeTimeout, IdleTimeout이 추가되어, 위조된 주소에서 쏟아지는 단일 패킷이 더 이상 서버 메모리를 채우지 못합니다. 이들 모두 값을 높이거나 0으로 설정해 예전 동작으로 되돌릴 수 있습니다.
고성능 엔진에는 긴 수정 목록이 적용되었습니다. 여러 정리 경로에서의 메모리 및 핸들 누수와 크래시, 수락 직후 클라이언트가 연결을 끊는 경우, 정리 도중 서버가 중지될 때 연결이 두 번 해제되는 문제, 워커 스레드를 켰을 때의 use after free, 그리고 처리하는 메시지마다 버퍼가 유실되는 문제입니다. HTTP keep-alive는 전혀 동작하지 않아서 요청마다 연결이 닫혔고 서버는 TIME_WAIT 상태의 소켓으로 가득 찼습니다. Linux에서는 HTTP 요청마다 파싱된 요청의 일부가 누수되었고, 모든 워커가 하나의 연결 큐를 공유해서 한두 개의 스레드가 거의 모든 작업을 처리했습니다.
여기에 두 가지 새 옵션이 더해졌으며 둘 다 기본적으로 꺼져 있습니다. 하나는 keep-alive 프로브와 유휴 타임아웃으로, 반쯤 열린 소켓이 더 이상 쌓이지 않게 합니다. 다른 하나는 새 연결을 워커 스레드에 라운드 로빈으로 분배하는 기능입니다.
Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Time := 60; // seconds idle before probing
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Interval := 10; // seconds between probes
Server.IOHandlerOptions.KeepAliveTimeout := 120; // seconds
자세히 보기: IOCP 및 EPOLL 서버를 위한 TCPKeepAlive와 KeepAliveTimeout. 엔진 수정 가운데 여럿의 바탕이 된 패치를 제공해 준 Andrea에게 감사드립니다.
프로토콜: STOMP, MQTT, AMQP 그리고 HTTP/2
STOMP에 가장 많은 작업이 들어갔습니다. 이제 정상적인 Disconnect는 브로커가 영수증으로 확인해 줄 때까지 기다리므로, 연결을 닫을 때 아무것도 잃지 않습니다. 메시지는 브로커가 보낸 그대로 전달되며 본문을 읽을 때 content-length를 사용하므로 줄바꿈과 바이너리 0을 포함할 수 있습니다. 하나의 WebSocket 메시지에 여러 개가 담긴 프레임도 모두 처리되고, 두 메시지에 걸쳐 나뉜 프레임은 다시 조립되며, 바이너리 프레임도 더 이상 무시되지 않습니다. ACK와 NACK는 협상된 버전이 요구하는 헤더를 보내고, 하트비트는 서버가 연결을 확인한 뒤에만 시작됩니다.
oSTOMP.DisconnectTimeout := 10000; // ms to wait for the receipt, 0 = return at once
oSTOMP.ACKEx(vMessageId, vSubscriptionId);
ShowMessage('STOMP ' + oSTOMP.NegotiatedVersion);
MQTT는 더 이상 브로커가 거부하는 패킷을 만들지 않습니다. 사용자 이름은 있고 비밀번호는 없는 CONNECT나, 더 큰 속성 블록을 담은 MQTT 5 패킷이 그런 예입니다. 또한 MQTT 5 클라이언트가 패킷 끝을 넘어 읽는 문제도 없어졌습니다. 잘린 패킷이 있으면 메모리에서 그 뒤에 있던 내용을 속성 값으로 애플리케이션에 넘겨주곤 했습니다. 이제는 CONNACK로 돌아온 Keep Alive부터 Topic Alias만 담아 도착한 메시지까지, 브로커가 알려 주는 내용을 그대로 따릅니다. QoS 2 발행 경로는 올바른 후속 확인을 보내고, 브로커가 거부한 메시지를 무한히 재시도하는 대신 폐기하며, 합리적인 일정에 따라 재시도합니다.
AMQP 1.0 클라이언트는 이제 불량 브로커로부터 보호됩니다. 잘게 나뉘어 도착하는 프레임, 잘못된 헤더 크기, 너무 깊이 중첩된 메시지, 엄청난 양의 메모리로 부풀도록 조작된 작은 메시지 등이 대상입니다. AMQP 0.9.1과 1.0의 기본 최대 프레임 크기는 사실상 무제한에서 1 MB로 바뀌었습니다. HTTP/2 헤더 압축은 조작된 헤더로부터 보호되고, 연결은 한 번도 열린 적 없는 스트림에 대한 DATA 프레임, PRIORITY 프레임 폭주, 스트림 번호 재사용, 빈 continuation 폭주를 거부하며, 서버는 줄바꿈이나 널을 포함한 헤더 이름과 값을 거부해 요청 스머글링을 방지합니다. 리셋된 스트림으로 인한 메모리 증가와 약 100건의 요청 후 발생하던 "CONCURRENT STREAM limit has been exceeded" 문제도 모두 수정되었습니다.
MCP 서버
이제 도구는 입력에 대한 완전한 JSON Schema를 제공할 수 있습니다. items를 갖춘 배열, 열거형, 정수 및 nullable 타입, 중첩 객체, additionalProperties를 선언할 수 있는데, 일부 MCP 클라이언트는 이를 요구하며 없으면 거부합니다. 서버는 2025-11-25 프로토콜의 메타데이터도 제공합니다. readOnlyHint 주석과 주석 제목, 도구 아이콘, 서버 제목, 웹사이트와 아이콘, 그리고 tools/list 작업 지원 선언입니다.
이미 MCP 서버를 운영 중이라면 두 가지 수정이 중요합니다. 서버가 클라이언트가 GET으로 여는 이벤트 스트림에 내부 연결 id를 메시지로 기록했고, VS Code GitHub Copilot 같은 클라이언트가 이를 "Failed to parse message"로 보고했습니다. 그리고 origin 검사는 브라우저가 절대 보내지 않는 헤더가 요청에 있을 때만 실행되어, 정작 막으려던 상황에서는 전혀 실행되지 않았습니다. 사용자가 방문한 웹 페이지가 자기 컴퓨터의 MCP 서버에 접근해 도구 목록을 얻고, 실행하고, 결과를 읽을 수 있었던 것입니다. 이제 origin은 브라우저의 사전 검사까지 포함해 모든 요청에서 확인됩니다.
MCPServer.MCPOptions.HTTPStreamable.AllowedOrigins.Add('https://*.example.com');
암호화폐 거래소
고객 두 분의 제보가 이 작업의 대부분을 이끌었습니다. HTTP 오류 상태로 실패한 요청은 이제 서버가 응답한 헤더를 함께 알려 주므로, 429의 Retry-After나 거래소가 반환하는 요청 제한 카운터를 드디어 읽을 수 있습니다. 미리 만들어진 API 클라이언트는 EsgcHTTPAPIProtocolException을 발생시키는데, 이는 이전에 발생하던 예외를 상속하므로 기존 핸들러는 그대로 동작합니다.
try
vResponse := oBinance.GetAggregateTrades('BTCUSDT');
except
on E: EsgcHTTPAPIProtocolException do
begin
if E.ErrorCode = 429 then
Sleep(E.RetryAfterMs);
vWeight := E.GetHeader('X-MBX-USED-WEIGHT-1M');
// E.ResponseHeaders holds the complete list
end;
end;
모든 거래소 클라이언트는 재접속 후 겨우 몇 밀리초 된 연결에서 전체 구독 목록을 한 번에 몰아서 다시 보냈고, 그래서 초당 메시지 수를 제한하는 거래소는 연결을 곧바로 닫았으며 이 과정이 반복되었습니다. 이제 재전송은 속도를 조절해 이루어지고, Binance에서는 결합된 프레임으로 전송됩니다. 여러분이 보내는 메시지에 대한 새로운 클라이언트 측 스로틀도 추가되었습니다.
oBinance.Throttle.Enabled := True;
oBinance.Throttle.MaxMessages := 4; // per window
oBinance.Throttle.IntervalMs := 1000;
// paced reconnect replay is on by default:
// oBinance.Throttle.PaceResubscribe := False; restores the old burst
// subscribe a whole watchlist with ONE frame
oBinance.SubscribeStreams(['btcusdt@trade', 'ethusdt@trade', 'bnbusdt@trade']);
Binance가 Spot 사용자 데이터 스트림의 기반이던 listenKey 엔드포인트를 폐지했습니다. 그래서 계정, 주문, 잔고 업데이트는 이제 Binance WebSocket API에서 오며, 컴포넌트가 스스로 여는 두 번째 연결을 통해 전달되고 재접속 후에는 갱신됩니다. 이벤트는 같은 형태로 도착하므로 기존 핸들러는 계속 동작하지만, 새 구독은 서명이 필요합니다. 이제 Binance.ApiKey뿐 아니라 Binance.ApiSecret도 설정해야 합니다. Binance.us와 Futures는 여전히 listenKey를 사용합니다. USD-M Futures 시장 데이터는 이제 두 개의 주소에서 제공되며, 새 Binance.FuturesStreamEndpoint 속성으로 선택합니다(기본값은 bfsePublic, 집계 거래와 마크 가격, kline, 청산 스트림에는 bfseMarket).
그 밖에도 수정된 내용이 있습니다. OKX의 가격과 수량은 전송 전에 소수점 다섯 자리로 반올림되었기 때문에, 더 작은 틱을 쓰는 종목의 주문은 여러분이 요청한 주문과 달랐고, 0.00001보다 작은 값은 0으로 전송되었습니다. OKX와 KuCoin의 keepalive는 이제 WebSocket 핑 대신 각 거래소가 요구하는 텍스트 핑을 보내고, pong이 돌아오지 않으면 재접속합니다. 자세히 보기: Binance 요청 제한: 배치, 페이싱 그리고 읽을 수 있는 429.
zlib 1.3.1과 자재 명세서
함께 제공되는 zlib이 1.2.12에서 1.3.1로 올라갔고, 이로써 inflate의 힙 과다 읽기인 CVE-2022-37434가 해결되었습니다. 링크되는 오브젝트는 Delphi 7부터 Delphi 13까지, 32비트와 64비트로 다시 빌드했고 모든 컴파일러에서 검증했습니다. 부수적인 수정으로, Delphi 10 Seattle 64비트에서는 zlib 오브젝트가 전혀 링크되지 않고 32비트 오브젝트를 선택해 컴파일에 실패하던 문제도 고쳤습니다.
이제 모든 설치 프로그램이 sbom.cdx.json도 함께 설치합니다. 라이브러리를 구성하는 컴포넌트와 그 버전, 라이선스를 나열한 CycloneDX 소프트웨어 자재 명세서입니다. Enterprise와 All-Access는 맞춤 제작된 Indy와 그 zlib의 버전을 명시하고, Core, Standard, Professional은 Indy가 Delphi 또는 C++ Builder에 포함된 버전임을 기록합니다. 설치 프로그램을 빌드할 때 에디션별로 생성되므로 언제나 실제로 설치한 내용과 일치합니다. 자세히 보기: sgcWebSockets와 sgcOpenAPI의 zlib 1.3.1과 이제 sgcWebSockets는 자체 SBOM을 설치합니다.
보안 수정
TLS 외에도 이번 릴리스는 여러 취약점을 막았습니다. 아래 목록을 확인하시고, 이 컴포넌트 가운데 하나라도 애플리케이션에서 사용 중이라면 업그레이드하세요.
- OAuth2 서버. 리디렉션 주소를 등록된 주소와 전혀 비교하지 않았기 때문에 인증 코드가 요청이 지정한 주소로 그대로 전송되었고, 조작된 링크로 사용자의 코드를 다른 사람의 사이트에 전달할 수 있었습니다. 이제는 정확히 일치해야 합니다. 로그인 페이지도 애플리케이션 이름과 요청된 스코프를 표시하기 전에 정리합니다.
- WebAuthn 서버. FIDO 메타데이터 파일을 확인 없이 신뢰했고, 루트 인증서가 설정되지 않으면 검사를 아예 건너뛰었기 때문에, 위조된 파일로 서버가 가짜 인증기를 수락하게 만들 수 있었습니다. 등록 시 검사하는 인증서 확장 디코더도 아무것도 확인하지 않아서, 잘리거나 깊이 중첩된 확장으로 서버가 관련 없는 메모리를 읽게 만들 수 있었습니다.
- Files 프로토콜. 들어오는 파일 이름을 거의 그대로 사용했기 때문에, 상대방이
../../../file같은 이름을 보내 디스크의 어디든 읽고, 쓰고, 삭제할 수 있었습니다. 삭제 쪽에는 보호 장치가 전혀 없었습니다. - WinHTTP 클라이언트. 이제 기본적으로 서버 인증서를 검증합니다. 이전에는 알 수 없는 인증 기관, 잘못된 호스트 이름, 만료된 유효 기간을 무시했기 때문에
wss연결이 모르는 사이에 가로채질 수 있었습니다. - WebSocket 프로토콜. 여는 핸드셰이크를 표준이 요구하는 대로 검증하고, 잘못된 프레임은 수락하는 대신 거부하며, 핸드셰이크 키는 보안 난수 생성기를 사용하고, 사용자 이름과 비밀번호 확인은 비밀번호가 정답에 가깝든 아니든 같은 시간이 걸립니다.
- HTTP 클라이언트. 응답 헤더에 대한 제한이 전혀 적용되지 않아서, 서버가 클라이언트의 메모리가 바닥날 때까지 끝없이 헤더를 보낼 수 있었습니다. 제한 없음을 뜻하는
MaxHeaderLines값 0은 오히려 반대로 동작해Content-Length와Location을 포함한 모든 응답 헤더를 버렸습니다. - OpenAPI 서버.
EnforceSecurity를 켰지만 검증 이벤트를 지정하지 않은 경우, api key나Authorization헤더를 담고 있기만 하면 어떤 요청이든 오퍼레이션에 도달했습니다. 이제 그런 요청에는 401로 응답합니다. - 파서. STUN 속성 일곱 개와 여러 SOCKS5 응답이 패킷 끝을 넘어 읽혔고, 상대방이 하나의 데이터그램에 여러 레코드를 보내면 DTLS 연결이 읽기 버퍼 끝을 넘어 썼습니다.
놓치기 쉬운 것이 하나 더 있습니다. 한 컴포넌트에서 다른 컴포넌트로 복사할 때 대부분의 TLS 옵션이 유실되었습니다. IO 핸들러, ALPN 프로토콜, OpenSSL 옵션만 복사되었기 때문에 인증서 파일, 비밀번호, 루트 인증서, TLS 버전, VerifyCertificate는 비어 있는 채로 남았고, 그런 식으로 설정된 컴포넌트는 결국 아무것도 검증하지 않았습니다.
그 밖의 추가 사항
- WebTransport. 세션에 새
DatagramsSupported속성이 추가되어 데이터그램을 실제로 보낼 수 있는지 알려 줍니다. - 소켓. 연결의 소켓 바인딩에
SetSendTimeout에 대응하는 새SetReceiveTimeout메서드가 추가되어, 응답이 끊긴 연결이 읽고 있던 스레드를 멈춰 세우는 대신 깔끔하게 실패합니다. - 브리지 서버. 브리지에서 호스팅되는 DataSnap 또는 WebBroker 애플리케이션이 설정한 쿠키가 1899년 날짜로 직렬화되어 브라우저가 이미 만료된 것으로 보고 버렸고, HTTP.sys 브리지는 여러 쿠키를 하나로 줄였습니다. 이제 모든 속성을 갖춘 세션 쿠키로 전송됩니다.
- 오류. 실패한 TLS 연결은 OpenSSL이 알려 준 진짜 원인이 버려지는 바람에 "error:00000006:lib(0):func(0):EVP lib" 같은 메시지를 보고하곤 했습니다. 이제 ML-KEM-768은 OpenSSL 3.5 이상이 필요하다고 설명하고 발견된 버전을 보여 주며, RC2 40비트 같은 오래된 알고리즘을 사용하는 PKCS#12 파일은 legacy provider를 활성화하는 방법을 안내합니다.
- 예외. TCP 및 HTTP/2 컴포넌트의
OnException이벤트에서 무작위로 발생하던 크래시를 수정했습니다. 이벤트가 실행되기 전에 예외를 발생시킨 스레드가 예외를 파괴했기 때문에, 핸들러가 해제된 메모리를 읽고 잘못된 클래스 이름을 보고했습니다.
이번 릴리스와 함께 새로 나온 것들
라이브러리와 함께 제공되는 두 가지가 이번 달에 각각 별도의 글로 소개되었습니다. 하나는 REST 서버 컴포넌트로, CORS와 메트릭, 헬스 엔드포인트, 멀티테넌시, 그리고 명세 파일 하나를 라우팅과 검증, 보안, Swagger UI로 바꿔 주는 OpenAPI 플러그인을 갖춘 REST API 전용 HTTP 서버입니다. 다른 하나는 .proto 파일을 Delphi 유닛으로 변환하는 코드 생성기 sgcProtoBuf입니다. 자세히 보기: TsgcHTTPRESTServer: 새로운 REST 서버 컴포넌트, REST 서버 + OpenAPI, 사용자, 멀티테넌시 그리고 메트릭 그리고 sgcProtoBuf: .proto 파일에서 Delphi 유닛으로.
.NET 에디션
sgcWebSockets .NET 2026.8은 이번 릴리스에서 공통되는 절반을 담고 있습니다. SChannel 관련 작업은 모두 포함되어 있습니다. 무시되던 버전, 복제된 연결에서 유실되던 설정, 검사 없는 재협상, 끝내 완료되지 않던 TLS 1.3 연결, 알아채지 못하던 끊긴 연결, 제한 없는 핸드셰이크와 시작 시 경쟁 상태, 여기에 닫기 전 종료 알림과 서버 측 클라이언트 인증서 검증까지입니다. IOCP 및 EPOLL 수정, WebSocket 핸드셰이크와 프레임 검증, MQTT와 STOMP, AMQP, HTTP/2 강화, OAuth2와 WebAuthn, MCP, Files 프로토콜 보안 수정, 그리고 거래소 관련 변경(Binance Spot 사용자 데이터 스트림, 속도를 조절한 재접속 재전송, OKX와 KuCoin의 keepalive)도 함께 포함됩니다. 영수증을 기다리는 정상적인 STOMP Disconnect와 WebSocket 서버의 제어 프레임 제한도 이곳에서 새로 추가되었습니다.
업그레이드
2026.8은 기존 2026.x 프로젝트에 그대로 적용할 수 있는 업그레이드이며, 빌드하기 전에 알아 둘 것이 두 가지 있습니다. Binance Spot 사용자 데이터 스트림이 이제 구독에 서명하므로 Binance.ApiKey와 함께 Binance.ApiSecret도 설정해야 합니다. 그리고 WebSocket 서버가 이제 무제한 대신 기본적으로 동시 연결 10,000개를 수락하므로, 그보다 많은 연결을 운영한다면 MaxConnections 값을 높이거나 0으로 설정하세요.
나머지는 모두 여러분이 요청하기 전까지 꺼져 있습니다. 폐기 확인, 버전 하한선, strong crypto, 클라이언트 인증서 검증, IOCP 및 EPOLL 엔진의 keep-alive, 메시지 스로틀, MCP 허용 origin 목록은 모두 기본적으로 예전 동작을 유지합니다.
활성 구독을 보유한 고객은 고객 영역에서, 또는 esegece.com/products/websockets/download에서 새 빌드를 다운로드할 수 있습니다.
질문이나 피드백이 있거나 마이그레이션에 도움이 필요하신가요? 문의해 주세요. 코드를 직접 작성한 사람들이 답변해 드립니다.
