VaaL2004
@VaaL2004

Как принимать длинный net.socket?

Здравствуйте! Появилась задача наладить общение программы и сайта (сайт на node.js), программа отдаёт таблицы в json виде по tcp сокету.
Однако я уткнулся в одну проблемку, node.js получает 64Кб и обрезает всё остальное, после чего говорит лаконичное, но вполне логичное: [SyntaxError: Unexpected end of input] и следом получает остаток.

Так вот собственно вопрос, как правильно в Node.js принимать длинные сообщения через net.socket?

Сейчас ответ принимаю так:

function parseAnswer(ans) {
	// Превращаем буфер в строку
	ans=ans.toString();
	//Убираем \r\n
	ans=ans.replace(/(\r\n|\n|\r)/gm,"");
	//Режем на массив
	return ans.split('*');
}


tcp.on('data', function(data) {
				array=parseAnswer(data);

				switch (array[0]) {
					case 'stat1':
					if (array[1]==0) {
						socket.emit('cl_stat1');
					}
					break;
                                 }
});
  • Вопрос задан
  • 3330 просмотров
Решения вопроса 1
pi314
@pi314
Президент Солнечной системы и окрестностей
Все замечательно, только вот обрабатывать пришедшие данные в простейшем случае нужно не на 'data', а на 'end'! А на 'data' нужно тупо (еще лучше - умно!) накапливать пришедшие данные и продолжать верить в светлое будущее, т.е. в то, что когда-нибудь придет 'end'.

Тогда, если совсем тупо, то как-то так:
var data = '';
tcp.on('data', function(chunk){
  data += chunk;
});

tcp.on('end', function(){
  parseAnswer(data);
  ...
});

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

Но есть еще два момента.

Первый. 'end' может и не придти... сеть упадет, программу убьют, злобный админ свитч передернет. Короче, эта ситуация - отдельный повод для дальнейших размышлений. Для этого еще есть как минимум 'error', на который тоже хорошо бы как-то осмысленно реагировать.

Второй. Написанное выше справедливо только для односторонней передачи через сокет. Если же через тот же сокет нужно слать ответ или др. данные, то делать это нужно иначе. (На случай, если "socket.emit('cl_stat1');" в коде имеет отношение к этому же сокету.) Тогда нужно самому определять (на 'data'), когда закончились данные клиента (а для этого нужно знать протокол обмена, в простейшем случае - признак конца пакета, который искать в данных), и слать ответ, и потом уже, если нужно, самому закрывать сокет. Тогда событие 'end' не поможет, т.к. оно прилетает только, если сокет на другом конце уже сам пытается закрыться.
var data = '';
tcp.on('data', function(chunk){
  data += chunk;
  if(packetComplete(data)){
    parseAnswer(data);
    ...
    sendResponse();
  }
});

В 64К тоже нет ничего волшебного. В любой ОС между сокетом "в программе" и сетью есть как минимум один буфер. Разные языки предоставляют разные средства воздействия на него, либо вызов flush(), блокирующий, пока данные не будут физически отправлены, либо, как нод, чей метод socket.write()
Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory. 'drain' will be emitted when the buffer is again free.
The optional callback parameter will be executed when the data is finally written out - this may not be immediately.

B принципе, данные могут приходить частями любого размера. Если программист сам не заботится о моменте отправки (а это далеко не всегда полезно!), буфер отправляется, как только заполнился. И то же самое справедливо и для приема. Прикиньте, что бы было, если бы через сокет слали не несколько десятков K, а, скажем, 10 GB, а в системе, скажем, на все про все (включая нод) всего 4 GB? Откуда бы было взять бедному ноду столько памяти, чтоб потом за рaз отдать все одной строкой - не в магазин же сбегать... Отсюда и многочисленные события 'data' при приеме "одной, но большой" строки.

Так что, вопрос, по сути, нужно бы было назвать "Как работать с сокетами" :)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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