Server-Sent Events, WebSocket'lerin sessiz kuzeni sayılırdı: sunucunun birbiri ardına küçük metin olayları yazdığı, hiç bitmeyen sade bir HTTP yanıtı. Birden bire her yerde karşımıza çıkıyor. LLM API'lerinin akış hâlindeki yanıtları SSE olarak geliyor, MCP sunucuları bunu Streamable HTTP üzerinden konuşuyor, ve panolar, bildirimler ile iş ilerleme akışları, HTTP'yi geçiren her proxy'den geçtiği için bunu kullanıyor.
sgcWebSockets 2026.10, Delphi, C++Builder ve .NET için bir EventSource istemcisi olan TsgcSSEClient'ı ekliyor. Akışı bir arka plan iş parçacığında okur, size her olayı türü, verisi ve id'siyle birlikte verir, bağlantı koptuğunda kendi kendine yeniden bağlanır, ve arada hiçbir şey kaybolmasın diye Last-Event-ID ile devam eder. Bileşen şu anki indirmenin bir parçası değildir. 2026.10 sürümüyle, her editörde gelecektir.
TsgcSSEClient tipli olayları alıyor, bağlantıyı kaybediyor ve Last-Event-ID ile devam ediyor. YouTube'da da izleyin.
SSE Neden Şimdi Önemli
Bir SSE akışı, kısa bloklardan oluşan bir text/event-stream yanıtıdır: türü belirten isteğe bağlı bir event: satırı, bir veya daha fazla data: satırı, isteğe bağlı bir id:, ve olayı sonlandıran boş bir satır. Bir sunucu, istemciye yeniden bağlanmadan önce ne kadar bekleyeceğini söylemek için retry: da gönderebilir. Format basittir, ama doğru bir istemcinin bir satırı herhangi bir yerden bölen parçaları, birden çok satıra yayılan veriyi, CR, LF ve CRLF satır sonlarını, ve nerede kaldığını hatırlayan bir yeniden bağlanmayı ele alması gerekir. İşte TsgcSSEClient'ın sizin için yaptığı kısım budur.
Hızlı Başlangıç
sgcHTTP_SSE_Client birimini ekleyin, URL'yi ayarlayın, OnEvent'i işleyin ve Open'ı çağırın. Bir bearer token gibi istek başlıkları, her biri bir Ad: Değer satırı olarak Headers'a girer, ve yeniden bağlanmalar dahil her bağlantıda gönderilir.
procedure TForm1.FormCreate(Sender: TObject);
begin
oSSE := TsgcSSEClient.Create(nil);
oSSE.URL := 'https://www.example.com/events';
oSSE.Headers.Add('Authorization: Bearer ' + FToken);
oSSE.OnEvent := OnSSEEvent;
oSSE.OnError := OnSSEError;
oSSE.Open;
end;
procedure TForm1.OnSSEEvent(Sender: TObject; const aEvent: TsgcSSEEvent);
begin
if aEvent.EventType = 'alert' then
ShowMessage(aEvent.Data)
else
Memo1.Lines.Add(aEvent.EventType + ' #' + aEvent.Id + ': ' + aEvent.Data);
end;
procedure TForm1.OnSSEError(Sender: TObject; const aError: string);
begin
Memo1.Lines.Add('error: ' + aError);
end;
Her olay tiplidir. EventType, event:'ten gelen adı taşır, böylece tek bir işleyici alert, tick veya sunucunuzun icat ettiği herhangi bir türü yönlendirebilir. Bir VCL veya FireMonkey uygulamasında olaylar varsayılan olarak ana iş parçacığına teslim edilir, bu yüzden işleyiciler arayüze doğrudan dokunabilir. NotifyEvents bunu değiştirir. OnOpen ve OnClose, akışın ne zaman başlayıp bittiğini size bildirir, ve ReadyState, sseConnecting, sseOpen veya sseClosed değerini bildirir.
İstemci, sunucuya bir tarayıcının EventSource'unun tepki verdiği şekilde tepki verir:
text/event-streamile gelen bir 200 akışı açar. Yönlendirmeler izlenir.- Bir 204 No Content, sunucunun istemcinin durmasını istediği anlamına gelir. Hata vermeden kapanır ve yeniden bağlanmaz.
- Başka herhangi bir durum kodu veya yanlış bir içerik türü,
OnError'ı ve ardındanOnClose'ı tetikler, ve istemci yeniden bağlanmaz. Bir 401'i sonsuza kadar yeniden denemek kimseye yardımcı olmaz. - Bir ağ hatası veya okuma zaman aşımı
OnError'ı tetikler, ardından istemci yeniden bağlanır. Sunucu akışı sadece sonlandırdığında da istemci yeniden bağlanır.
Last-Event-ID ile Devam Etme
Sunucu olaylarına bir id: alanı verdiğinde, istemci sonuncusunu LastEventId içinde tutar ve her yeniden bağlanmada bunu Last-Event-ID başlığında gönderir. Sunucu bu başlığı okur ve o olaydan sonra devam eder, böylece kopan bir bağlantı hiçbir mesaja mal olmaz ve hiçbirini tekrarlamaz. Tek bir oturum içinde bunun için hiç koda gerek yoktur.
Uygulama yeniden başladıktan sonra devam etmek için, durduğunuzda LastEventId'yi kaydedin ve Open'dan önce geri yükleyin. Özellik, Close'dan sonra da değerini korur, ve Open'dan önce ayarlanan bir değer, ilk istekle birlikte gönderilir.
procedure TForm1.StartStream;
begin
if FileExists('sse_last_id.txt') then
oSSE.LastEventId := Trim(TFile.ReadAllText('sse_last_id.txt'));
oSSE.Open;
end;
procedure TForm1.StopStream;
begin
oSSE.Close;
TFile.WriteAllText('sse_last_id.txt', oSSE.LastEventId);
end;
Devam etmek, sunucunun iş birliği yapmasını gerektirir: olaylarıyla birlikte id: göndermeli ve Last-Event-ID başlığına uymalıdır.
Kontrol Ettiğiniz Bir Yeniden Bağlanma Politikası
Yeniden bağlanma varsayılan olarak açıktır, 3 saniyelik bir gecikmeyle. ReconnectOptions, bunu sunucunuzun hak ettiği herhangi bir politikaya dönüştürür: bir çarpanla üstel geri çekilme (backoff), gecikme için bir üst sınır, binlerce istemcinin aynı milisaniyede geri gelmemesi için rastgele jitter, ve deneme sayısı için bir sınır.
procedure TForm1.SetupReconnect;
begin
oSSE.ReconnectOptions.Interval := 1000;
oSSE.ReconnectOptions.Backoff := True;
oSSE.ReconnectOptions.BackoffMultiplier := 2.0;
oSSE.ReconnectOptions.MaxInterval := 30000;
oSSE.ReconnectOptions.Jitter := 0.2;
oSSE.ReconnectOptions.MaxAttempts := 10;
oSSE.OnReconnect := OnSSEReconnect;
end;
MaxAttempts, ardışık başarısızlıkları sayar, ve sayaç her bağlantı açıldığında yeniden başlar, bu yüzden haftalarca çalışan ve arada bir ağ aksaklığı yaşayan bir istemci hiçbir zaman denemeleri tükenmez. Sunucunun da söz hakkı vardır: bir retry: alanı, oturumun geri kalanı için Interval'ın yerini alır. Son söz sizindir, her denemeden önce hesaplanan gecikmeyle tetiklenen OnReconnect'te:
procedure TForm1.OnSSEReconnect(Sender: TObject; aAttempt: Integer;
var aDelay: Integer; var aCancel: Boolean);
begin
// stop after the fifth failed attempt, otherwise wait at least 2 seconds
if aAttempt > 5 then
aCancel := True
else if aDelay < 2000 then
aDelay := 2000;
end;
TLS, Proxy ve Kimlik Doğrulama
Akış bir TsgcHTTP1Client ile okunur, ve OnBeforeConnect her bağlantı denemesinden önce onu size teslim eder. HTTP istemcisinin yapabildiği her şeyi SSE istemcisi de yapabilir: TLS seçenekleri, bir proxy, temel kimlik doğrulama veya daha uzun bir okuma zaman aşımı.
procedure TForm1.OnSSEBeforeConnect(Sender: TObject;
const aHTTP: TsgcHTTP1Client);
begin
aHTTP.TLSOptions.Version := tls1_2;
aHTTP.Proxy.Enabled := True;
aHTTP.Proxy.Host := '192.168.1.10';
aHTTP.Proxy.Port := 8080;
aHTTP.ReadTimeout := 60000;
end;
OnBeforeConnect ve OnReconnect her zaman arka plan iş parçacığında çalışır, bu yüzden arayüzü bunların dışında tutun.
LLM Akışları ve MCP İçin Ayrıştırıcı
Çoğu zaman uzun ömürlü bir EventSource'a hiç ihtiyacınız olmaz. stream: true ile yapılan bir LLM sohbet tamamlaması, yanıtı SSE olan bir POST'tur, ve bir MCP Streamable HTTP yanıtı da SSE olabilir. Bu durumlar için istemcinin içindeki ayrıştırıcı herkese açıktır: TsgcSSEParser. Ona, ağın teslim ettiği şekilde, herhangi bir boyutta parçalar hâlinde ham bayt veya metin verin; her tam olay için OnEvent'i ve geçerli her retry: alanı için OnRetry'ı tetikler. Bir parça, bir satırın veya bir UTF-8 karakterinin ortasında bitebilir, ve ayrıştırıcı kalanını bir sonraki çağrıya kadar saklar.
procedure TForm1.ParseStream;
begin
FParser := TsgcSSEParser.Create;
FParser.OnEvent := OnParserEvent;
// chunks arrive as the network delivers them, split anywhere
FParser.Feed('event: content_block_delta'#10'data: {"delta":{"text":"Hel');
FParser.Feed('lo"}}'#10#10'event: message_stop'#10);
FParser.Feed(TEncoding.UTF8.GetBytes('data: {}'#10#10));
// start again for the next response
FParser.Reset;
end;
procedure TForm1.OnParserEvent(Sender: TObject; const aEvent: TsgcSSEEvent);
begin
Memo1.Lines.Add(aEvent.EventType + ' ' + aEvent.Data);
end;
Bu üç parça iki olay üretir: tam JSON'u {"delta":{"text":"Hello"}} olan content_block_delta ve message_stop. Reset, bir sonraki yanıttan önce yarım kalmış herhangi bir olayı atar, ve LastEventId size ayrıştırıcının gördüğü son id'yi söyler.
.NET İçin C#
sgcWebSockets'in .NET sürümü, esegece.sgcWebSockets ad alanında aynı isimlere sahip aynı bileşene sahiptir. Headers, Ad: Değer dizgilerinden oluşan bir listedir ve olaylar sıradan .NET olaylarıdır.
using esegece.sgcWebSockets;
string token = args.Length > 0 ? args[0] : "";
var sse = new TsgcSSEClient();
sse.URL = "https://www.example.com/events";
sse.Headers.Add("Authorization: Bearer " + token);
if (File.Exists("sse_last_id.txt"))
sse.LastEventId = File.ReadAllText("sse_last_id.txt").Trim();
sse.ReconnectOptions.Backoff = true;
sse.ReconnectOptions.MaxInterval = 30000;
sse.OnEvent += (sender, e) => Console.WriteLine($"{e.EventType} #{e.Id}: {e.Data}");
sse.OnError += (sender, error) => Console.WriteLine("error: " + error);
sse.Open();
Console.ReadLine();
sse.Close();
File.WriteAllText("sse_last_id.txt", sse.LastEventId);
TsgcSSEParser da oradadır; bir byte[], onun bir dilimi veya bir string için Feed aşırı yüklemeleriyle birlikte.
Demoları Deneyin
Her iki sürüm de tamamen çevrimdışı çalışan bir demoyla gelir. Bu demo, 127.0.0.1 üzerinde, 5580 portunda, aynı uygulama içinde küçük bir SSE sunucusu barındırır; bu sunucu id: içeren numaralandırılmış olayları akışa alır, message, tick ve alert türlerini döndürür, bir retry: alanı gönderir ve aldığı Last-Event-ID'den sonra devam eder. Bağlantıyı koparın ve istemcinin yeniden bağlanıp bir sonraki id'den, boşluksuz ve yinelemesiz olarak devam etmesini izleyin.
- Delphi:
Demos\20.HTTP_Protocol\17.SSE_Client_Component - .NET:
demos\20.HTTP_Protocol\17.SSE_Client_Component, ki bu da sırayı, yinelemeleri ve devam başlığını kendi başına denetleyen bir/selftestanahtarına sahiptir
Kullanıma Sunulma
TsgcSSEClient ve TsgcSSEParser, Delphi, C++Builder ve .NET için, her editörde, sgcWebSockets 2026.10 ile geliyor. Bugün indirebileceğiniz sürümde yer almıyorlar. 2026.10 çıktığında, indirme sayfasında olacak, ve bileşen SGC HTTP palet sekmesine kaydedilecek.
Her özellik, olay ve devam etme kılavuzunu içeren tam referans, TsgcSSEClient yardımında bulunur. sgcWebSockets'in Server-Sent Events ile yaptığı diğer her şey için SSE ürün sayfasına bakın.
Sırada Ne Var
Sorularınız, geri bildiriminiz veya taşıma konusunda yardıma mı ihtiyacınız var? İletişime geçin. Kodu yazan kişilerden bir yanıt alacaksınız.
