TsgcGRPCClient 컴포넌트는 외부 런타임 없이 gRPC를 Delphi와 C++Builder로 가져와요. sgcWebSockets Enterprise 에디션의 일부이며 Windows, macOS, Linux, iOS, Android에서 실행돼요. 이 가이드에서는 클라이언트가 어떻게 동작하는지, 어떻게 구성하는지, 그리고 Delphi에서 네 가지 gRPC 호출 유형을 각각 어떻게 수행하는지 설명해요.
동작 방식
gRPC는 HTTP/2 위에서 프레이밍된 Protocol Buffers 메시지예요. 각 메시지는 HTTP/2 스트림에서 길이 접두사가 붙은 페이로드로 전송되고, 요청은 content-type: application/grpc와 grpc-timeout 같은 헤더를 실어 보내며, 최종 상태는 grpc-status와 grpc-message 트레일러로 도착해요.
sgcWebSockets는 이미 완전한 HTTP/2 스택을 제공하므로, TsgcGRPCClient는 TsgcHTTP2Client 전송 위에 올라가요. 직렬화된 요청 바이트를 넘겨주면 프레이밍, 헤더, 타임아웃 작업을 처리하고, HTTP/2 스트림을 열고, 응답과 트레일러를 파싱해 타입이 지정된 TsgcGRPCResponse로 되돌려줘요. 클라이언트가 원시 TBytes를 다루기 때문에, 이미 사용 중인 어떤 Protocol Buffers 라이브러리와도 함께 쓸 수 있어요.
클라이언트 설정하기
gRPC 채널은 HTTP/2 연결이에요. TsgcHTTP2Client를 생성하고 호스트와 포트를 지정한 다음, gRPC 컴포넌트의 Client 속성에 할당하세요. TLS의 경우 HTTP/2 클라이언트는 OpenSSL 또는 Windows SChannel을 사용해요. 로컬 평문 서버(h2c)의 경우 TLS를 False로 설정하세요.
uses
sgcHTTP2, sgcGRPC_Client, sgcGRPC_Classes, sgcGRPC_Types;
var
HTTP2: TsgcHTTP2Client;
GRPC: TsgcGRPCClient;
begin
HTTP2 := TsgcHTTP2Client.Create(nil);
HTTP2.Host := 'grpc.example.com';
HTTP2.Port := 443;
HTTP2.TLS := True; // False for a local h2c server
HTTP2.TLSOptions.IOHandler := iohOpenSSL; // or iohSChannel on Windows
GRPC := TsgcGRPCClient.Create(nil);
GRPC.Client := HTTP2;
end;
채널 구성하기
채널 전체에 적용되는 설정은 ChannelOptions에 있어요. 메시지별 gzip 압축을 켜고, 와이어 콘텐츠 타입을 선택하고, 메시지와 metadata 크기 제한을 높일 수 있어요.
// gzip-compress outgoing messages
GRPC.ChannelOptions.Compression := grpcGzip; // grpcNoCompression, grpcGzip, grpcDeflate, grpcSnappy
// application/grpc+proto (default) or application/grpc+json
GRPC.ChannelOptions.ContentType := grpcProto; // or grpcJSON
// raise the limits for large messages
GRPC.ChannelOptions.MaxMessageSize := 16 * 1024 * 1024;
GRPC.ChannelOptions.MaxMetadataSize := 64 * 1024;
Metadata와 인증
커스텀 헤더는 gRPC metadata로 전달돼요. 모든 호출에서 보내려면 DefaultMetadata에 추가하세요. 인증 토큰이나 추적 헤더를 두기에 보통 가장 알맞은 곳이에요.
GRPC.DefaultMetadata.Add('authorization', 'Bearer eyJ...');
GRPC.DefaultMetadata.Add('x-api-key', 'my-api-key');
데드라인과 취소
호출별 타임아웃은 표준 grpc-timeout 헤더로 전송되므로, 서버는 클라이언트와 같은 시점에 작업을 포기할 수 있어요. 진행 중인 스트리밍 호출은 스트림이 열릴 때 반환된 스트림 id를 전달하여 CancelCall로 언제든지 중단할 수 있어요.
단항 호출
단항 호출은 하나의 요청을 보내고 하나의 응답을 받아요. Call은 응답이 도착할 때까지 블로킹하고, StatusCode, StatusMessage, 원시 Data 바이트(또는 DataString), 그리고 Trailers를 담은 TsgcGRPCResponse를 반환해요.
var
oResponse: TsgcGRPCResponse;
begin
oResponse := GRPC.Call('helloworld.Greeter', 'SayHello', RequestBytes);
if oResponse.StatusCode = grpcOK then
Memo1.Text := oResponse.DataString
else
ShowMessage('gRPC error ' + oResponse.StatusMessage);
end;
UI 반응성을 유지하려면 CallAsync를 사용하세요. 즉시 반환되며 응답은 OnGRPCResponse 이벤트를 통해 전달돼요.
GRPC.OnGRPCResponse := GRPCResponse;
GRPC.CallAsync('helloworld.Greeter', 'SayHello', RequestBytes);
procedure TForm1.GRPCResponse(Sender: TObject; const Response: TsgcGRPCResponse);
begin
if Response.StatusCode = grpcOK then
Memo1.Text := Response.DataString;
end;
서버 스트리밍
서버 스트리밍에서는 하나의 요청을 보내면 서버가 메시지 스트림을 반환해요. 각 메시지는 OnGRPCStreamMessage를 발생시키고, OnGRPCStreamEnd는 최종 상태와 함께 한 번 발생해요.
GRPC.OnGRPCStreamMessage := GRPCStreamMessage;
GRPC.OnGRPCStreamEnd := GRPCStreamEnd;
GRPC.ServerStreamingCall('chat.Feed', 'Subscribe', RequestBytes);
procedure TForm1.GRPCStreamMessage(Sender: TObject; aStreamId: Integer;
const aData: TBytes);
begin
Memo1.Lines.Add(DecodeMessage(aData));
end;
클라이언트 스트리밍
클라이언트 스트리밍은 정반대예요. 메시지 스트림을 밀어 보내면 서버가 한 번 응답해요. 스트림을 열고, 각 메시지를 보낸 다음, 스트림을 닫아 단일 응답을 읽어요.
var
vStreamId: Integer;
oResponse: TsgcGRPCResponse;
begin
vStreamId := GRPC.OpenClientStream('upload.Service', 'Send');
GRPC.SendStreamMessage(vStreamId, ChunkBytes1);
GRPC.SendStreamMessage(vStreamId, ChunkBytes2);
oResponse := GRPC.CloseClientStream(vStreamId);
if oResponse.StatusCode = grpcOK then
ShowMessage('Upload accepted');
end;
양방향 스트리밍
양방향 스트리밍은 단일 HTTP/2 스트림 위에서 전이중 교환을 실행해요. 양쪽이 원할 때 언제든지 보낼 수 있어요. 스트림을 열고, 필요에 따라 메시지를 보내고, 들어오는 메시지는 OnGRPCStreamMessage에서 처리하고, 끝나면 닫으세요.
var
vStreamId: Integer;
begin
vStreamId := GRPC.OpenBidiStream('chat.Room', 'Connect');
GRPC.SendBidiMessage(vStreamId, EncodeMessage('hello'));
// ... incoming messages arrive on OnGRPCStreamMessage ...
GRPC.CloseBidiStream(vStreamId);
end;
상태 코드와 오류 처리
모든 응답은 grpcOK부터 표준 gRPC 집합(grpcNOT_FOUND, grpcUNAVAILABLE, grpcDEADLINE_EXCEEDED, grpcUNAUTHENTICATED 등)에 이르기까지 타입이 지정된 StatusCode를 실어 보내요. 비동기 및 스트리밍 호출의 경우, OnGRPCError는 OK가 아닌 gRPC 상태를 보고하고 OnGRPCException은 전송 또는 연결 실패를 보고해요.
GRPC.OnGRPCError := GRPCError;
procedure TForm1.GRPCError(Sender: TObject; aStreamId: Integer;
aStatusCode: TsgcGRPCStatusCode; const aStatusMessage: string);
begin
Memo1.Lines.Add(Format('gRPC error %d: %s', [Ord(aStatusCode), aStatusMessage]));
end;
자동 재시도
클라이언트가 실패한 호출을 대신 재시도할 수 있어요. RetryPolicy를 활성화하고, 시도 횟수와 백오프를 설정하고, 재시도를 유발해야 하는 상태 코드를 나열하세요. 이는 일시적인 grpcUNAVAILABLE 실패에 대한 전형적인 구성이에요.
GRPC.RetryPolicy.Enabled := True;
GRPC.RetryPolicy.MaxAttempts := 4;
GRPC.RetryPolicy.InitialBackoff := 200; // ms
GRPC.RetryPolicy.BackoffMultiplier := 2.0;
GRPC.RetryPolicy.RetryableStatusCodes :=
GRPC.RetryPolicy.RetryableStatusCodes + [grpcUNAVAILABLE, grpcRESOURCE_EXHAUSTED];
로깅이나 토큰 갱신 같은 횡단 관심사 로직의 경우, Interceptors 체인에 항목을 추가하세요. 이는 한 곳에서 모든 호출을 감싸요.
다음 단계
이 범용 클라이언트 위에, sgcWebSockets는 Google Cloud gRPC 서비스(Pub/Sub, Speech-to-Text, Translation, Vision, Natural Language, Cloud Storage, BigQuery, Vertex AI)를 위한 타입이 지정된 클라이언트를 제공하므로, protobuf를 직접 손으로 조립하는 대신 고수준 메서드를 호출할 수 있어요. 바로 실행할 수 있는 샘플은 Demos\21.GRPC\01.GRPC_Client에 있고, 전체 레퍼런스는 gRPC Client 제품 페이지에 있어요.
질문이 있거나 시작하는 데 도움이 필요하신가요? 문의하기. 코드를 작성한 사람들로부터 직접 답변을 받으실 거예요.
