IdTCPServer, odpowiedź do serwera . IdTCPClient , odbiór od serwera
TIdTCPServer
wysyła odpowiedź do konkretnego klienta za pomocąAContext.Connection.IOHandler.WriteLn(...)
wewnątrz zdarzenia OnExecute
, OnConnect
lub w dowolnym wątku, w którym dysponujemy kontekstem danego klienta. TIdTCPClient
odbiera tę odpowiedź synchronicznie wywołując jedną z metod odczytu (najczęściej ReadLn
, ReadBytes
, ReadStream
) po wysłaniu zapytania albo w dedykowanym wątku/Timerze, gdy połączenie ma pozostawać otwarte.Kluczowe punkty
• Serwer i klient muszą uzgodnić terminator (np. CRLF) lub długość ramki.
• Read*
i Write*
są operacjami blokującymi – stosuj wątki albo asynchroniczne wywołania, by nie zamrozić GUI.
• Każde połączenie klienta ma własny kontekst (TIdContext
); serwer może wysłać wiadomość do wszystkich lub wybranego klienta iterując po IdTCPServer.Contexts
.
• Obsługuj wyjątki (EIdConnClosedGracefully
, EIdReadTimeout
, EIdSocketError
) i zawsze zamykaj połączenie w bloku finally
.
TCP zapewnia dwukierunkowy strumień bajtów. W Indy:
TIdTCPServer
. AContext
. TIdTCPClient
. Po Connect
obiekt działa synchronicznie.procedure TMainFrm.IdTCPServerExecute(AContext: TIdContext);
var
Cmd, Resp: string;
begin
try
Cmd := AContext.Connection.IOHandler.ReadLn; // blokujące
Resp := ProcessCommand(Cmd); // własna logika
AContext.Connection.IOHandler.WriteLn(Resp); // odpowiedź
except
on E: EIdConnClosedGracefully do
Exit; // klient zamknął
on E: Exception do
begin
AContext.Connection.IOHandler.WriteLn('ERROR:' + E.Message);
AContext.Connection.Disconnect;
end;
end;
end;
Procesowanie pakietów binarnych: najpierw wyślij długość (Int32
w sieciowym porządku bajtów), potem WriteBuffer
.
function TClientCore.QueryServer(const ACmd: string): string;
begin
IdTCPClient.Host := '127.0.0.1';
IdTCPClient.Port := 8080;
IdTCPClient.ReadTimeout := 5000; // ms
IdTCPClient.Connect;
try
IdTCPClient.IOHandler.WriteLn(ACmd); // zapytanie
Result := IdTCPClient.IOHandler.ReadLn; // odpowiedź (blokuje)
finally
IdTCPClient.Disconnect;
end;
end;
Długotrwałe połączenie: utwórz wątek TThread
i pętlę
while not Terminated do
if IdTCPClient.IOHandler.InputBufferIsEmpty then
Sleep(10)
else
HandleData(IdTCPClient.IOHandler.ReadLn);
procedure TBroadcaster.Broadcast(const AMsg: string);
var
LList: TList;
Ctx : TIdContext;
begin
LList := IdTCPServer.Contexts.LockList;
try
for Ctx in LList do
TThread.Queue(nil, procedure // wysyłanie z wątku GUI opcjonalne
begin
Ctx.Connection.IOHandler.WriteLn(AMsg);
end);
finally
IdTCPServer.Contexts.UnlockList;
end;
end;
Dbaj o synchronizację – Contexts.LockList/UnlockList
zabezpiecza dostęp.
ReadTimeout
/ConnectTimeout
– unikasz wiecznego blokowania. TThread.Synchronize
/ TThread.Queue
. TThreadSafeStringList
.TIdIOTATCPServer
z poprawkami bezpieczeństwa TLS 1.3. TIdSSLIOHandlerSocketOpenSSL
.WriteStream
/ ReadStream
. IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
.finally IdTCPClient.Disconnect
i OnDisconnect
po stronie serwera. telnet
lub openssl s_client
do prostego sniffingu. GStack.CheckSocketsInitialized
. TThread.Queue
.TIdTCPClient
). W bardzo obciążonych systemach rozważ AsyncIO (np. libuv) albo IOCP na Windows. TIdConnectionIntercept
.Komunikacja Indy jest prosta: serwer w OnExecute
odczytuje komendę, generuje i wysyła odpowiedź przez WriteLn
; klient po Connect
wykonuje WriteLn
i synchronizacyjnie ReadLn
, lub trwale nasłuchuje w osobnym wątku. Klucz do stabilności – poprawne zamykanie połączeń, timeouty oraz nieblokowanie wątku GUI. Dzięki tym zasadom zbudujesz bezpieczny i responsywny system klient-serwer w Delphi.