Линейно-ориентированные потоки в Node.js - PullRequest
5 голосов
/ 04 июля 2011

Я занимаюсь разработкой многопроцессорного приложения с использованием Node.js.В этом приложении родительский процесс порождает дочерний процесс и связывается с ним по протоколу обмена сообщениями на основе JSON через канал.Я обнаружил, что большие сообщения JSON могут быть «обрезаны», так что один «кусок», отправляемый прослушивателю данных в канале, не содержит полного сообщения JSON.Кроме того, небольшие сообщения JSON могут быть сгруппированы в один и тот же блок.Каждое сообщение JSON будет разделено символом новой строки, и поэтому мне интересно, есть ли уже утилита, которая буферизует поток чтения канала так, чтобы он генерировал по одной строке за раз (и, следовательно, для моего приложения - один документ JSON)вовремя).Кажется, это довольно распространенный вариант использования, поэтому мне интересно, если это уже было сделано.

Буду признателен за любые рекомендации, которые кто-либо может предложить.Спасибо.

Ответы [ 4 ]

4 голосов
/ 04 июля 2011

Может быть, Педро перевозчик может вам помочь?

Carrier поможет вам внедрить новую линию расторгнутые протоколы через node.js.

Клиент может отправить вам куски линии и оператор будут только уведомлять вас на каждой заполненной строке.

2 голосов
/ 13 июня 2013

Мое решение этой проблемы заключается в отправке сообщений JSON, каждое из которых заканчивается специальным символом Unicode.Символ, который вы никогда не получите в строке JSON.Назовите его TERM.

Таким образом, отправитель просто делает "JSON.stringify (message) + TERM;"и пишет это.Затем получатель разбивает входящие данные в TERM и анализирует части с помощью JSON.parse (), что довольно быстро.Хитрость в том, что последнее сообщение может не анализироваться, поэтому мы просто сохраняем этот фрагмент и добавляем его в начало следующего сообщения, когда оно приходит.Получение кода выглядит следующим образом:

        s.on("data", function (data) {
        var info = data.toString().split(TERM);
        info[0] = fragment + info[0];
        fragment = '';

        for ( var index = 0; index < info.length; index++) {
            if (info[index]) {
                try {
                    var message = JSON.parse(info[index]);
                    self.emit('message', message);
                } catch (error) {
                    fragment = info[index];
                    continue;
                }
            }
        }
    });

Где «фрагмент» определяется где-то, где он будет сохраняться между порциями данных.

Но что такое TERM?Я использовал символ замены Unicode '\ uFFFD'.Можно также использовать технику, используемую в твиттере, где сообщения разделяются '\ r \ n', а твиты используют '\ n' для новых строк и никогда не содержат '\ r \ n'

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

1 голос
/ 04 июля 2011

Самое простое решение - отправлять длину данных json перед каждым сообщением в виде префикса фиксированной длины (4 байта?) И иметь простой синтаксический анализатор без кадров, который буферизует небольшие фрагменты или разбивает большие.

Вы можете попробовать node-binary , чтобы избежать написания парсера вручную. Посмотрите на scan(key, buffer) пример документации - он выполняет построчное чтение.

0 голосов
/ 17 августа 2017

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

const buf = ''
s.on('data', data => {
  buf += data.toString()
  const idx = buf.indexOf('\n')
  if (idx < 0) { return } // No '\n', no full message
  let lines = buf.split('\n')
  buf = lines.pop() // if ends in '\n' then buf will be empty
  for (let line of lines) {
    // Handle the line
  }
})
...