Streaming del cliente y bidireccional
Cree canales de streaming del cliente y de streaming bidireccional full-duplex para escenarios de alto rendimiento.
Streaming del cliente y bidireccional es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.
Streaming del cliente y streaming bidireccional
Además de las RPC unarias y el streaming del servidor, gRPC admite el streaming del cliente (el cliente envía muchos mensajes y el servidor responde una vez) y el streaming bidireccional (ambos lados envían varios mensajes simultáneamente a través de una conexión).
Streaming del cliente: definición de proto
Añada la palabra clave stream antes del tipo de solicitud. El cliente envía una secuencia de mensajes y, cuando termina, el servidor devuelve una única respuesta.
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; }Implementar el streaming del cliente en el servidor
Utilice IAsyncStreamReader<T> para leer los mensajes del cliente a medida que llegan. Llame a MoveNext() o itere con 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 };
}Invocar una RPC de streaming del cliente
Abra la llamada de streaming, escriba mensajes con RequestStream.WriteAsync() y, después, indique que ha terminado con CompleteAsync(). Espere la respuesta.
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");Streaming bidireccional: definición de proto
Añada stream en ambos lados para obtener una comunicación full-duplex. Tanto el cliente como el servidor pueden enviar mensajes en cualquier momento e independientemente.
service ChatService {
rpc Chat (stream ChatMessage) returns (stream ChatMessage);
}
message ChatMessage {
string user = 1;
string content = 2;
int64 sent_at = 3;
}Implementar el streaming bidireccional en el servidor
Lea de IAsyncStreamReader y escriba en IServerStreamWriter de forma simultánea. Utilice Task.WhenAll para ejecutar ambos bucles al mismo tiempo.
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);
}Streaming bidireccional desde el cliente
Envíe y reciba simultáneamente iniciando dos tareas: una para escribir mensajes y otra para leer las respuestas.
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;Control de flujo y backpressure
HTTP/2 incorpora control de flujo. Si el consumidor es lento, gRPC pausa automáticamente al emisor, lo que evita el desbordamiento de memoria. No almacene los mensajes en búfer manualmente; deje que el stream se encargue.
// 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 uploadsCierre parcial y finalización del stream
En el streaming bidireccional, cualquiera de los dos lados puede cerrar su mitad de escritura mientras continúa leyendo del otro. Esto permite que el cliente indique que ha terminado de enviar mientras sigue esperando las respuestas del 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);
}Usar canales para un streaming bidireccional seguro para subprocesos
Combine System.Threading.Channels con el streaming bidireccional para obtener un patrón limpio de productor-consumidor que distribuya mensajes de forma segura a muchos oyentes.
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);
}Caso real: canalización de análisis en tiempo real
Un servicio de ingesta de datos acepta un stream de eventos de telemetría de dispositivos IoT y transmite estadísticas agregadas en tiempo real: un caso de uso perfecto para el streaming bidireccional.
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 });
}
}Comprobación rápida
En el streaming del cliente, ¿cuándo envía el servidor su única respuesta?
Resumen: streaming del cliente y streaming bidireccional
Ideas clave:
- Streaming del cliente: el cliente envía muchos mensajes y el servidor envía una respuesta; es ideal para cargar archivos
- Streaming bidireccional: ambos lados envían mensajes de forma independiente; es ideal para chats y fuentes de datos en directo
- Utilice
ReadAllAsync()para consumir streams conawait foreach - Llame a
RequestStream.CompleteAsync()para cerrar parcialmente el lado de escritura del cliente - El control de flujo de HTTP/2 gestiona automáticamente el backpressure; no almacene streams completos en búfer
- System.Threading.Channels combina bien con el streaming bidireccional en escenarios de distribución a múltiples receptores
Preguntas frecuentes
¿La lección «Streaming del cliente y bidireccional» es gratis?
Sí — el texto completo de «Streaming del cliente y bidireccional» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Streaming del cliente y bidireccional»?
Cree canales de streaming del cliente y de streaming bidireccional full-duplex para escenarios de alto rendimiento. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C# Academy?
No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Streaming del cliente y bidireccional»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C# Academy?
Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Fundamentos de gRPC y Protobuf
- RPC unarios y streaming del servidor
- Streaming del cliente y bidireccional
- Plazos, cancelación e interceptores