0Pricing
C# Academy · Aula

Transmissão pelo cliente e bidirecional

Crie canais de transmissão pelo cliente e de transmissão bidirecional full-duplex para cenários de alto volume.

Transmissão pelo cliente e bidirecional é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.

Transmissão pelo cliente e transmissão bidirecional

Além das RPCs unárias e da transmissão pelo servidor, o gRPC oferece suporte à transmissão pelo cliente (o cliente envia várias mensagens e o servidor responde uma vez) e à transmissão bidirecional (ambos os lados enviam várias mensagens simultaneamente pela mesma conexão).

Transmissão pelo cliente: definição do proto

Adicione a palavra-chave stream antes do tipo de solicitação. O cliente envia uma sequência de mensagens e, quando termina, o servidor retorna uma única resposta.

service UploadService {
  // Client streams chunks, server returns a summary
  rpc UploadFile (stream FileChunk) returns (UploadSummary);
}

message FileChunk   { bytes data = 1; string filename = 2; }
message UploadSummary { int64 bytes_received = 1; string checksum = 2; }

Implementando a transmissão pelo cliente no servidor

Use IAsyncStreamReader<T> para ler as mensagens do cliente à medida que elas chegam. Chame MoveNext() ou itere com ReadAllAsync().

public override async Task<UploadSummary> UploadFile(
    IAsyncStreamReader<FileChunk> requestStream,
    ServerCallContext context)
{
    long totalBytes = 0;
    using var ms = new MemoryStream();

    await foreach (var chunk in requestStream.ReadAllAsync(context.CancellationToken))
    {
        await ms.WriteAsync(chunk.Data.Memory, context.CancellationToken);
        totalBytes += chunk.Data.Length;
    }

    var checksum = ComputeMd5(ms.ToArray());
    return new UploadSummary { BytesReceived = totalBytes, Checksum = checksum };
}

Chamando a transmissão pelo cliente no cliente

Abra a chamada de transmissão, escreva mensagens com RequestStream.WriteAsync() e sinalize a conclusão com CompleteAsync(). Aguarde a resposta.

using var call = client.UploadFile();

var fileBytes = await File.ReadAllBytesAsync("large-file.bin");
const int chunkSize = 64 * 1024; // 64 KB

for (int offset = 0; offset < fileBytes.Length; offset += chunkSize)
{
    var chunk = fileBytes.Skip(offset).Take(chunkSize).ToArray();
    await call.RequestStream.WriteAsync(new FileChunk
    {
        Filename = "large-file.bin",
        Data = Google.Protobuf.ByteString.CopyFrom(chunk)
    });
}

await call.RequestStream.CompleteAsync(); // signal end
var summary = await call;                // await server response
Console.WriteLine($"Uploaded {summary.BytesReceived} bytes");

Transmissão bidirecional: definição do proto

Adicione stream nos dois lados para obter comunicação duplexa completa. O cliente e o servidor podem enviar mensagens a qualquer momento, de forma independente.

service ChatService {
  rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}

message ChatMessage {
  string user    = 1;
  string content = 2;
  int64  sent_at = 3;
}

Implementando a transmissão bidirecional no servidor

Leia de IAsyncStreamReader e escreva em IServerStreamWriter simultaneamente. Use Task.WhenAll para executar os dois ciclos ao mesmo tempo.

public override async Task Chat(
    IAsyncStreamReader<ChatMessage> requestStream,
    IServerStreamWriter<ChatMessage> responseStream,
    ServerCallContext context)
{
    // Broadcast to all connected clients
    var readTask = Task.Run(async () =>
    {
        await foreach (var msg in requestStream.ReadAllAsync(context.CancellationToken))
        {
            _chatHub.Broadcast(msg);
        }
    });

    var writeTask = Task.Run(async () =>
    {
        await foreach (var msg in _chatHub.GetMessagesAsync(context.CancellationToken))
        {
            await responseStream.WriteAsync(msg);
        }
    });

    await Task.WhenAll(readTask, writeTask);
}

Transmissão bidirecional no cliente

Envie e receba simultaneamente iniciando duas tarefas — uma para escrever mensagens e outra para ler respostas.

using var call = client.Chat();

// Read task
var readTask = Task.Run(async () =>
{
    await foreach (var msg in call.ResponseStream.ReadAllAsync())
        Console.WriteLine($"{msg.User}: {msg.Content}");
});

// Write task
while (Console.ReadLine() is string text && text != "exit")
{
    await call.RequestStream.WriteAsync(
        new ChatMessage { User = "Alice", Content = text,
                          SentAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() });
}
await call.RequestStream.CompleteAsync();
await readTask;

Controle de fluxo e contrapressão

O HTTP/2 tem controle de fluxo integrado. Se o consumidor for lento, o gRPC pausará o remetente automaticamente, evitando o estouro de memória. Não armazene mensagens manualmente; deixe que a transmissão cuide disso.

// DO: Let gRPC flow control handle backpressure
await foreach (var chunk in requestStream.ReadAllAsync(ct))
{
    await ProcessChunkAsync(chunk); // naturally paced
}

// DON'T: Buffering all chunks defeats flow control
var allChunks = new List<FileChunk>();
await foreach (var chunk in requestStream.ReadAllAsync(ct))
    allChunks.Add(chunk); // may OOM on large uploads

Fechamento parcial e conclusão da transmissão

Na transmissão bidirecional, qualquer um dos lados pode fechar o próprio lado de escrita enquanto continua lendo do outro. Isso permite que o cliente sinalize que "terminou de enviar" enquanto ainda aguarda as respostas do servidor.

// Client signals it's done sending
await call.RequestStream.CompleteAsync(); // half-close

// Continue reading server responses after half-close
await foreach (var reply in call.ResponseStream.ReadAllAsync())
{
    Console.WriteLine(reply.Content);
}

Usando canais para uma transmissão bidirecional segura para threads

Combine System.Threading.Channels com a transmissão bidirecional para obter um padrão limpo de produtor e consumidor que distribui mensagens com segurança para vários ouvintes.

private readonly Channel<ChatMessage> _broadcast =
    Channel.CreateUnbounded<ChatMessage>();

// Producer: receives from each client stream
public async Task ReceiveLoopAsync(
    IAsyncStreamReader<ChatMessage> reader, CancellationToken ct)
{
    await foreach (var msg in reader.ReadAllAsync(ct))
        await _broadcast.Writer.WriteAsync(msg, ct);
}

// Consumer: writes to each client's response stream
public async Task SendLoopAsync(
    IServerStreamWriter<ChatMessage> writer, CancellationToken ct)
{
    await foreach (var msg in _broadcast.Reader.ReadAllAsync(ct))
        await writer.WriteAsync(msg);
}

Na prática: fluxo de análise em tempo real

Um serviço de ingestão de dados aceita um fluxo de eventos de telemetria de dispositivos IoT e transmite estatísticas agregadas de volta em tempo real — um caso de uso perfeito para a transmissão bidirecional.

service TelemetryService {
  rpc StreamTelemetry(stream TelemetryEvent) returns (stream AggregatedStats);
}

// Server implementation sends a rolling aggregate every 100 events:
public override async Task StreamTelemetry(
    IAsyncStreamReader<TelemetryEvent> requests,
    IServerStreamWriter<AggregatedStats> responses,
    ServerCallContext context)
{
    int count = 0;
    double total = 0;
    await foreach (var e in requests.ReadAllAsync(context.CancellationToken))
    {
        total += e.Value;
        if (++count % 100 == 0)
            await responses.WriteAsync(
                new AggregatedStats { Count = count, Average = total / count });
    }
}

Verificação rápida

Na transmissão pelo cliente, quando o servidor envia sua única resposta?

Recapitulação: transmissão pelo cliente e transmissão bidirecional

Principais conclusões:

  • Transmissão pelo cliente: o cliente envia várias mensagens e o servidor envia uma resposta — ideal para enviar arquivos
  • Bidirecional: ambos os lados enviam de forma independente — ideal para conversas e fluxos de dados ao vivo
  • Use ReadAllAsync() para consumir transmissões com await foreach
  • Chame RequestStream.CompleteAsync() para fechar parcialmente o lado de escrita do cliente
  • O controle de fluxo do HTTP/2 gerencia a contrapressão automaticamente — não armazene transmissões inteiras em buffer
  • System.Threading.Channels combina bem com a transmissão bidirecional em cenários de distribuição

Perguntas Frequentes

A aula “Transmissão pelo cliente e bidirecional” é grátis?

Sim — o texto completo de “Transmissão pelo cliente e bidirecional” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.

O que vou aprender em “Transmissão pelo cliente e bidirecional”?

Crie canais de transmissão pelo cliente e de transmissão bidirecional full-duplex para cenários de alto volume. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar C# Academy?

Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Transmissão pelo cliente e bidirecional”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de C# Academy?

Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Fundamentos de gRPC e Protobuf
  2. RPCs unários e transmissão pelo servidor
  3. Transmissão pelo cliente e bidirecional
  4. Prazos, cancelamento e interceptadores
← Voltar para C# Academy