Ответ
Bidirectional streaming (двунаправленная потоковая передача) — это один из четырех типов вызовов в gRPC, при котором и клиент, и сервер могут отправлять последовательность сообщений друг другу асинхронно через одно установленное сетевое соединение. Это позволяет организовать полноценный двусторонний диалог.
Как это выглядит в .proto-файле:
service ChatService {
// Клиент отправляет поток MessageRequest, сервер отвечает потоком MessageResponse
rpc StartConversation (stream MessageRequest) returns (stream MessageResponse);
}
message MessageRequest {
string text = 1;
}
message MessageResponse {
string text = 1;
int64 timestamp = 2;
}
Типичные сценарии использования:
- Чат-приложения и онлайн-игры (обмен сообщениями в реальном времени).
- Синхронизация данных (клиент отправляет изменения, сервер отправляет подтверждения и обновления).
- Real-time мониторинг и дашборды (сервер пушит обновления метрик, клиент может отправлять запросы на изменение интервала).
Пример реализации сервера на C#:
public override async Task StartConversation(
IAsyncStreamReader<MessageRequest> requestStream,
IServerStreamWriter<MessageResponse> responseStream,
ServerCallContext context)
{
// Задача 1: Чтение потока запросов от клиента
var readTask = Task.Run(async () =>
{
await foreach (var message in requestStream.ReadAllAsync())
{
Console.WriteLine($"Client said: {message.Text}");
// Можно обработать сообщение и, например, отправить ответ в другой задаче
}
});
// Задача 2: Отправка потока ответов клиенту (например, broadcast уведомлений)
var writeTask = Task.Run(async () =>
{
int count = 0;
while (!context.CancellationToken.IsCancellationRequested)
{
await responseStream.WriteAsync(new MessageResponse
{
Text = $"Server notification #{count++}",
Timestamp = DateTime.UtcNow.Ticks
});
await Task.Delay(TimeSpan.FromSeconds(5), context.CancellationToken);
}
});
await Task.WhenAll(readTask, writeTask); // Ожидаем завершения обеих задач
}
Ключевые преимущества:
- Эффективность: Одно долгоживущее соединение вместо множества отдельных HTTP-запросов (как в REST).
- Гибкость и асинхронность: Клиент и сервер могут отправлять данные независимо, без блокировки на ожидание ответа.
- Реальное время: Идеально подходит для сценариев с низкой задержкой и постоянным обменом данными.