Пакеты иногда соединяются - PullRequest
5 голосов
/ 29 января 2012

Я пытаюсь создать простой сервер / приложение на Erlang.
Мой сервер инициализирует сокет с gen_tcp:listen(Port, [list, {active, false}, {keepalive, true}, {nodelay, true}]), а клиенты соединяются с gen_tcp:connect(Server, Port, [list, {active, true}, {keepalive, true}, {nodelay, true}]).Сообщения, полученные от сервера, проверяются защитниками, такими как {tcp, _, [115, 58 | Data]}.

. Проблема в том, что пакеты иногда объединяются при отправке или получении и, таким образом, вызывают неожиданное поведение, так как охранники считают следующий пакет частью переменной.

Есть ли способ убедиться, что каждый пакет отправляется как одно сообщение в процесс получения?

Ответы [ 3 ]

10 голосов
/ 29 января 2012

Обычный TCP - это потоковый протокол без понятия границ пакетов (как сказал Альнитак).

Обычно вы отправляете сообщения в любом UDP-протоколе (который имеет ограниченный размер для каждого пакета и может быть получен не по порядку).) или TCP с использованием протокола в рамке.

В рамке означает, что каждое сообщение имеет префикс с размером заголовка (обычно 4 байта), который указывает, как долго это сообщение.

В erlang вы можете добавить {packet, 4} к вашим опциям сокета, чтобы получить оформленное поведение пакета поверх TCP.

при условии, что обе стороны (клиент / сервер) используют {пакет, 4}, тогда вы получите только целые сообщения.

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

0 голосов
/ 09 декабря 2017

Вам необходимо внедрить разделитель для ваших пакетов. Одним из решений является использование специального символа; или что-то подобное.

Другое решение - сначала отправить размер пакета. PacketSizeInBytes: Тело

Затем прочитайте предоставленное количество байтов из вашего сообщения. Когда вы в конце, вы получили весь свой пакет.

Никто не упоминает, что TCP может также разделить ваше сообщение на несколько частей (разделить ваш пакет на два сообщения).

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

0 голосов
/ 29 января 2012

Вы, вероятно, видите эффект алгоритма Нейгла, который предназначен для увеличения пропускной способности путем объединения небольших пакетов в один большой пакет.

Вам необходим эквивалент Эрланга для включения опции сокета TCP_NODELAY насокет отправки.

РЕДАКТИРОВАТЬ ах, я вижу, вы уже установили это.Хм.TCP на самом деле не раскрывает границы пакетов для прикладного уровня - по определению это протокол stream .

Если границы пакетов важны, вам следует рассмотреть вместо этого использование UDP или убедиться, что каждый пакетВы отправляете ограничены каким-либо образом.Например, в TCP-версии DNS каждое сообщение имеет префикс 2-байтового заголовка, который сообщает другому концу, сколько данных ожидать в следующем фрагменте.

...