Lapish72
@Lapish72

Нужно ли дробить данные при отправке через SignalR?

Есть клиент-серверное решение с использованием SignalR: обычные клиенты, сервер и админ. Обычный клиент отправляет данные серверу, а потом сервер перенаправляет их админу(ам). В какой-то момент при отправке больших данных клиентом серверу(как выяснилось больше 32kb) получал ошибку и пришлось на сервере добавить в параметры это:

services.AddSignalR(o =>
{
    o.MaximumReceiveMessageSize = null;
});

Да, сейчас все работает, но правильно ли это? Или включение этой опции спасает даже при отправке условно данных на 1гб?

Я думаю разбить отправку по частям, но проблема в том, что отправляемые данные - коллекция классов(пример IReadOnlyCollection details, у которого есть внутри еще коллекции разного размера.

public class ChangeSet
{
    //разные свойства

    //какой-то список    
}

public class Details
{
    //разные свойства

    public List<ChangeSet> Added { get; set; }

    public List<ChangeSet> Removed { get; set; }
}

Думаю в такой ситуации нужно именно делить по байтам. Т.е, порядок действий должен быть такой:
  1. Клиент после аутентификации получает от сервера максимальный размер отправляемых данных.
  2. Клиент перед каждой отправкой любых данных должен отправлять их не как (IReadOnlyCollection details), а как (byte[] chunk, int current, int total)
  3. Сервер при каждом получении данных должен их сохранять и если current == total, то он пытается преобразовать byte [] chunks в IReadOnlyCollection details. Если ошибка, то удаляем из списка все полученные данные от клиента.
  4. Если успешно преобразовали данные, то в таком же порядке уже отправляем админу и он при получении их сам преобразует.
  5. При отключении клиента нужно удалять все полученные данные по ConnectionId.
  • Вопрос задан
  • 77 просмотров
Решения вопроса 1
AshBlade
@AshBlade Куратор тега C#
Просто хочу быть счастливым
Да, сейчас все работает, но правильно ли это? Или включение этой опции спасает даже при отправке условно данных на 1гб?


На ASP.NET Core есть ограничение на размер запроса в 50 Мб (или около того). Нам это не подходило - мы увеличили лимит. Но проблема лежит в другом - аллокация памяти. Большие чанки заставляют аллоцировать объекты в LOH. А там они могут лежать долго и не выгружаться.

Я думаю разбить отправку по частям, но проблема в том, что отправляемые данные - коллекция классов


Судя по примеру класса Details вроде ничего не мешает отправить сначала Added, а затем Removed. А если и это не поможет, то можно стримить каждый элемент: например, сначала отправляешь кол-во элементов, а потом по одному за раз.
Смысл в том, чтобы не сериализовать один большой объект.

А если у тебя 1Гб. то это скорее файл. Его лучше чанками отправлять и на диск сохранять. А по завершении отправки начинать читать (не полностью в память загружать, а постепенно)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы