0Pricing
C# Academy · Leçon

Flux du client et flux bidirectionnels

Créez des canaux de flux côté client et de flux bidirectionnels en duplex intégral pour les scénarios à haut débit.

Flux du client et flux bidirectionnels est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Flux client et flux bidirectionnel

Au-delà des RPC unaires et du flux serveur, gRPC prend en charge le flux client (le client envoie de nombreux messages et le serveur répond une fois) et le flux bidirectionnel (les deux parties envoient plusieurs messages simultanément sur une seule connexion).

Flux client : définition du fichier proto

Ajoutez le mot-clé stream avant le type de requête. Le client envoie une séquence de messages et, lorsqu’il a terminé, le serveur renvoie une réponse unique.

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; }

Implémenter un flux client sur le serveur

Utilisez IAsyncStreamReader<T> pour lire les messages du client à mesure de leur arrivée. Appelez MoveNext() ou parcourez-les avec 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 };
}

Appeler un flux client depuis le client

Ouvrez l’appel de flux, écrivez les messages avec RequestStream.WriteAsync(), puis signalez la fin avec CompleteAsync(). Attendez la réponse.

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");

Flux bidirectionnel : définition du fichier proto

Ajoutez stream des deux côtés pour une communication en duplex intégral. Le client et le serveur peuvent envoyer des messages à tout moment, indépendamment l’un de l’autre.

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

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

Implémenter un flux bidirectionnel sur le serveur

Lisez depuis IAsyncStreamReader et écrivez dans IServerStreamWriter simultanément. Utilisez Task.WhenAll pour exécuter les deux boucles en parallèle.

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);
}

Flux bidirectionnel depuis le client

Envoyez et recevez simultanément en lançant deux tâches — l’une pour écrire les messages et l’autre pour lire les réponses.

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;

Contrôle de flux et régulation de la pression

HTTP/2 intègre un contrôle de flux. Si le consommateur est lent, gRPC met automatiquement l’émetteur en pause, ce qui évite un dépassement de mémoire. Ne mettez pas les messages en mémoire tampon manuellement ; laissez le flux s’en charger.

// 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

Fermeture partielle et fin du flux

Dans un flux bidirectionnel, chaque partie peut fermer sa moitié dédiée à l’écriture tout en continuant à lire celle de l’autre. Cela permet au client de signaler « terminé d’envoyer » tout en continuant d’attendre les réponses du serveur.

// 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);
}

Utiliser des canaux pour un flux bidirectionnel sûr entre threads

Combinez System.Threading.Channels avec le flux bidirectionnel pour obtenir un modèle producteur-consommateur clair, qui distribue en toute sécurité les messages à de nombreux écouteurs.

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);
}

Cas concret : pipeline d’analyse en temps réel

Un service d’ingestion de données accepte un flux d’événements de télémétrie provenant d’appareils IoT et renvoie des statistiques agrégées en temps réel — un cas d’utilisation idéal du flux bidirectionnel.

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 });
    }
}

Vérification rapide

Dans un flux client, quand le serveur envoie-t-il son unique réponse ?

Récapitulatif : flux client et flux bidirectionnel

Points clés à retenir :

  • Flux client : le client envoie de nombreux messages et le serveur envoie une réponse — idéal pour téléverser des fichiers
  • Flux bidirectionnel : les deux parties envoient indépendamment — idéal pour les discussions instantanées et les flux de données en direct
  • Utilisez ReadAllAsync() pour consommer les flux avec await foreach
  • Appelez RequestStream.CompleteAsync() pour fermer partiellement le côté écriture du client
  • Le contrôle de flux HTTP/2 gère automatiquement la régulation de la pression — ne mettez pas les flux entiers en mémoire tampon
  • System.Threading.Channels s’associe bien au flux bidirectionnel pour les scénarios de distribution

Questions Fréquemment Posées

La leçon « Flux du client et flux bidirectionnels » est-elle gratuite ?

Oui — le texte complet de « Flux du client et flux bidirectionnels » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Flux du client et flux bidirectionnels » ?

Créez des canaux de flux côté client et de flux bidirectionnels en duplex intégral pour les scénarios à haut débit. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Flux du client et flux bidirectionnels » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Fondamentaux de gRPC et Protobuf
  2. RPC unaires et flux du serveur
  3. Flux du client et flux bidirectionnels
  4. Échéances, annulation et intercepteurs
← Retour à C# Academy