Потоковая передача клиента

Последнее обновление: 27.11.2022

Рассмотрим потоковую передачу сообщений от клиента на сервер.

Проект сервера

Сначала в проекте сервера определим следующий файл metanit.proto:

syntax = "proto3";

package metanit;

message Request{ 
	string content = 1;
}

message Response{ 
	string content = 1;
}

service Messenger{
  // клиентская потоковая передача
  rpc ClientDataStream (stream Request) returns (Response);
}

Здесь сервис Messenger определяет метод ClientDataStream, который получает от клиента в потоке сообщения Request, где данные хранятся в свойстве content. А в ответ клиенту возвращается сообщение Response, которое также содержит строковое свойство content. Чтобы указать, что сервер посылает данные в потоке, перед сообщением Request указывается ключевое слово stream.

Далее в проекте сервера определим следующий класс MessengerService:

using Grpc.Core;
using Metanit;  // пространство имен сервиса MessengerService

public class MessengerService : Messenger.MessengerBase
{
    public override async Task<Response> ClientDataStream(IAsyncStreamReader<Request> requestStream, ServerCallContext context)
    {
        await foreach(Request request in requestStream.ReadAllAsync())
        {
            Console.WriteLine(request.Content);
        }
        Console.WriteLine("Все данные получены...");
        return new Response { Content = "все данные получены" };
    }
}

Метод сервиса в C# принимает два параметра: контекст ServerCallContext и объект IAsyncStreamReader, который типизируется типом запроса (здесь объект Request) и который позволяет считать данные из потока, то есть в примере выше это объект IServerStreamWriter<Response>

Для непосредственного считывания клиентских сообщений у IAsyncStreamReader вызывается метод ReadAllAsync(), который возвращает асинхронный поток и из которого можно извлечь каждое сообшение.

После получения всех сообщений клиента отправляем в ответ объект Response.

Далее в файле Program.cs подключим сервис MessengerService в приложение:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

// встраиваем MessengerService в обработку запроса
app.MapGrpcService<MessengerService>();
app.MapGet("/", () => "Hello World!");

app.Run();

И запустим проект сервера.

Проект клиента

Для тестирования сервиса определим проект консольного приложения. Добавим в него из проекта сервера файл metanit.proto. И в проекте консольного клиента в файле Program.cs определим следующий код:

using Grpc.Net.Client;
using Metanit;  // пространство имен класса Messenger.MessengerClient

// данные для отправки
string[] messages = { "Привет", "Как дела?", "Че молчишь?", "Ты че, спишь?", "Ну пока" };


// создаем канал для обмена сообщениями с сервером
// параметр - адрес сервера gRPC
using var channel = GrpcChannel.ForAddress("https://localhost:7229");

// создаем клиент
var client = new Messenger.MessengerClient(channel);

var call = client.ClientDataStream();

// посылаем каждое сообщение
foreach(var message in messages)
{
    await call.RequestStream.WriteAsync(new Request { Content= message });
}
// завершаем отправку сообшений в потоке
await call.RequestStream.CompleteAsync();
// получаем ответ сервера
Response response = await call.ResponseAsync;
Console.WriteLine($"Ответ сервера: {response.Content}");

После создания клиента начинаем взаимодействие с сервером:

var call = client.ClientDataStream();

Этот метод возвращает объект Grpc.Core.AsyncClientStreamingCall<Request, Response>. Его свойство RequestStream представляет поток отправки и с помощью метода WriteAsync() позволяет отправить на сервер в потоке сообщения:

foreach(var message in messages)
{
    await call.RequestStream.WriteAsync(new Request { Content= message });
}

В данном случае на сервер отправляются все строки из массива messages.

После завершения отправки данных надо закрыть поток методом CompleteAsync()

await call.RequestStream.CompleteAsync();

Вызов этого метода будет уведомлять сервер о том, что отправка сообщений завершена.

После завершения потока отправки мы можем получить ответ сервера с помощью свойства ResponseAsync:

Response response = await call.ResponseAsync;

Запустим клиент. Клиент отправит серверу все сообщения, и консоль сервера выведет все отправленные сообщения:

Привет
Как дела?
Че молчишь?
Ты че, спишь?
Ну пока
Все данные получены...
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850