Socket.io: как ограничить размер испускаемых данных от клиента сервером веб-сервера

У меня есть сервер node.js с socket.io. Мои клиенты используют socket.io для подключения к серверу node.js.

Данные передаются от клиентов к серверу следующим образом:

На клиенте

var Data = {'data1':'somedata1', 'data2':'somedata2'};
socket.emit('SendToServer', Data);

На сервере

socket.on('SendToServer', function(Data) {
    for (var key in Data) {
           // Do some work with Data[key]
    }
});

Предположим, что кто-то изменяет свой клиент и испускает на сервер действительно большой кусок данных. Например:

var Data = {'data1':'somedata1', 'data2':'somedata2', ...and so on until he reach for example 'data100000':'data100000'};
socket.emit('SendToServer', Data);

Из-за этого цикла на сервере...

for (var key in Data) {
       // Do some work with Data[key]
}

... серверу потребуется очень много времени, чтобы просмотреть все эти данные.

Итак, что является лучшим решением для предотвращения таких сценариев?

Спасибо

EDIT:

Я использовал эту функцию для проверки объекта:

function ValidateObject(obj) {
    var i = 0;
    for(var key in obj) {
        i++;
        if (i > 10) { // object is too big
            return false;
        }
    }
    return false;
}

Ответ 1

Поэтому проще всего проверить размер данных, прежде чем что-либо делать с ними.

socket.on('someevent', function (data) {
    if (JSON.stringify(data).length > 10000) //roughly 10 bytes
        return;

    console.log('valid data: ' + data);
});

Если честно, это немного неэффективно. Ваш клиент отправляет сообщение, socket.io анализирует сообщение в объект, а затем вы получаете событие и превращаете его обратно в строку.

Если вы хотите быть еще более эффективным, то на стороне клиента вы должны установить максимальную длину сообщений.

Для еще большей эффективности (и для защиты от злонамеренных пользователей), когда пакеты попадают в Socket.io, если длина становится слишком большой, их следует отбросить. Вам нужно будет либо придумать способ расширить прототипы, чтобы делать то, что вы хотите, либо вам нужно будет извлечь исходный код и изменить его самостоятельно. Кроме того, я не изучал протокол socket.io, но уверен, что вам придется сделать больше, чем просто "отбросить" пакет. Кроме того, некоторые пакеты являются ответными и ненадежными, поэтому вы не хотите возиться с ними.


Примечание: если вас интересует ТОЛЬКО количество ключей, вы можете использовать Object.keys(obj) который возвращает массив ключей:

if (Object.keys(obj).length > 10)
    return;

Ответ 2

Возможно, вы можете переключиться на socket.io-stream и напрямую обрабатывать входной поток.

Таким образом, вы должны присоединиться к кускам и, наконец, разобрать json-вход вручную, но у вас есть шанс закрыть соединение, когда длина входных данных превышает пороговое значение, которое вы решите.

В противном случае (при использовании подхода socket.io) ваш обратный вызов не будет вызываться до тех пор, пока не будет получен весь поток данных. Это не останавливает выполнение вашего основного потока js, но не использует память памяти, процессор и полосу пропускания.

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

if (Object.keys(data).length > n) return; // Where n is your maximum acceptable number of elements.
// But, anyway, this doesn't control the actual size of each element.

Ответ 3

Хорошо, я пойду со стороны Javascript... скажем, вы не хотите разрешать пользователям переходить определенный лимит данных, вы можете просто:

var allowedSize = 10;

Object.keys(Data).map(function( key, idx ) {
    if( idx > allowedSize ) return;
    // Do some work with Data[key]
});

это не только позволяет вам правильно циклически перемещаться по элементам вашего объекта, это позволяет вам легко ограничивать. (очевидно, это может также испортить ваши собственные предварительно заданные запросы)

Ответ 4

РЕДАКТИРОВАТЬ: вопрос заключается в том, как справляться с перегрузкой сервера. Вы должны проверить балансировку нагрузки с помощью gninx http://nginx.com/blog/nginx-nodejs-websockets-socketio/ - у вас могут быть дополнительные серверы, если один клиент создает узкое место. Остальные серверы будут доступны. Даже если вы решите эту проблему, есть еще другие проблемы, такие как клиент, отправляющий несколько небольших пакетов и так далее.

Socket.io-библиотека кажется немного проблематичной, управление слишком большими сообщениями недоступно на уровне websockets, три года назад был вызван pull-request, который дает представление о том, как это можно решить:

https://github.com/Automattic/socket.io/issues/886

Однако, поскольку WebSockets -protocol имеет конечный размер пакета, он позволит вам прекратить обработку пакетов, если определенный размер будет достигнут. Наиболее эффективным способом сделать это будет до того, как пакет будет преобразован в кучу JavaScript. Это означает, что вы должны обрабатывать преобразование WebSocket вручную - это то, что делает сокет .io для вас, но он не учитывает размер пакета.

Если вы хотите реализовать свой собственный уровень websocket, использование этой реализации WebSocket - node может быть полезно:

https://github.com/theturtle32/WebSocket-Node

Если вам не нужна поддержка старых браузеров, использование этого чистого websockets -approach может быть подходящим решением.

Ответ 5

Возможно, destroy buffer size - это то, что вам нужно.

Из wiki:

  • уничтожить размер буфера по умолчанию 10E7

Используется HTTP-транспортом. Сервер Socket.IO буферизует тела запросов HTTP до этого предела. Это ограничение не применяется к websocket или флеш-памяти.