Странное поведение OTP gen_tcp с настройками {packet,4} и использованием NodeJS «frame-stream» для связи TCP

#node.js #tcp #erlang #erlang-otp #gen-tcp

#node.js #tcp #erlang #erlang-otp #gen-tcp

Вопрос:

Некоторое время я пытался правильно оформить свои сообщения между моим сервером NodeJS и моим сервером erlang gen_tcp. Я успешно использовал {packet,line}, пока мне не пришлось отправлять большие сообщения с данными, и мне нужно было переключиться на кадрирование размера сообщения.

Я установил gen_tcp в {packet, 2}

и я использую библиотеку из: https://github.com/davedoesdev/frame-stream для стороны декодирования tcp NodeJS. Для него ТАКЖЕ установлен параметр размера пакета 2, и я попробовал вариант размера пакета 4.

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

Я провел тест, отправляя все более и более длинные сообщения из gen_tcp, а затем считывая первые четыре байта, полученные на стороне NodeJS:

в сообщении 127: ЗАГОЛОВОК: 0 0 0 127 Длина кадра 127

в сообщении 128: ЗАГОЛОВОК: 0 0 0 239 <—— Это должно быть 128 Длина кадра 239 <—— Это должно быть 128

Теории:

  • Некоторое несоответствие кодировки символов, поскольку оно находится на номере 128 (вероятно?)
  • Какая-то ошибка либо в gen_tcp, либо в библиотеке (маловероятно?)
  • Проклятие магии Вуду, которое заставляет меня работать в день прав человека (скорее всего)

Данные из wireshark показывают следующее:

Байты заголовка правильно кодируются gen_tcp после 128 символов, поскольку шестнадцатеричные значения выполняются следующим образом:

 [00][7e][...]  (126 length)
[00][7f][...]  (127 length)
[00][80][...]  (128 length)
[00][81][...]  (129 length)
 

Таким образом, должно быть, ошибка заключается в том, что библиотека на стороне NodeJS вызывает функции Node readUInt16BE(0) или readUInt32BE(0). Но я проверил конечность, и оба они имеют большой конец.

Если байты заголовка равны [A,B], то в двоичном формате эта ошибка возникает после [00000000 01111111]

Другими словами, readUInt16BE(0) считывает [000000000 10000000] как 0xef? что даже не является конечной опцией …?

Спасибо за любую помощь в решении этой проблемы.

С уважением

Дейл

Ответ №1:

Я понял это, проблема была вызвана установкой сокета для приема в кодировке UTF-8, которая поддерживает ascii до 127.

Не делайте этого: сокет.setEncoding(‘utf8’).

Теперь это кажется очевидным, но одну строку кода трудно определить.