Реализация протокола TLV через TCP

#c #python #tcp #protocol-buffers

#c #python #tcp #протокол-буферы

Вопрос:

В настоящее время я пытаюсь реализовать протокол (T) LV, который будет использоваться поверх TCP. Очень ранняя версия этого протокола была создана путем простой отправки одного сообщения на пару send-recv. (т.е. send(«сообщение для передачи» — recv(… )). Это действительно плохо с точки зрения пропускной способности — я думаю, потому что я отправляю действительно маленькие пакеты. Итак, теперь я пытаюсь переключиться на протокол LV, отправляя сразу несколько сообщений, разделенных только их соответствующей длиной (теперь я использую буферы протокола для сериализации моих данных).

Теперь у меня есть два вопроса:

  • В python я отправляю, выполняя

    sock.send(struct.pack("<H", len(gtMessage.SerializeToString())))
    sock.send(gtMessage.SerializeToString())

Если бы я сейчас поместил это в цикл и отправил несколько таких сообщений, я бы в конечном итоге столкнулся со своей старой проблемой, насколько я понимаю. Могу ли я как-то связать строку для отправки вместе?

  • В C я получаю сначала длину сообщения, а затем считываю количество байтов, указанное в поле длины.

Лучше ли с точки зрения производительности сначала прочитать все из TCP, а затем проанализировать его, или я могу прочитать одно сообщение, затем проанализировать его и только затем прочитать следующий бит из провода?

Редактировать: итак, после проведения дополнительных исследований я бы перефразировал первый вопрос следующим образом:

Является

     sock.send("somestring")
    sock.send("somestring")
  

то же, что

 sock.send("somestring" "somestring")
  

?

Ответ №1:

Выполнение двух отправок подряд может привести к отправке двух фактических пакетов, что не так уж и здорово. Чтобы исправить это, вы можете объединить две части самостоятельно или использовать writev (он же «собрать запись») или TCP_CORK при первой отправке, чтобы предотвратить ее самостоятельное превращение в пакет.

Что касается принимающей стороны, вы должны получить большой блок (столько, сколько сможете, до некоторого разумного предела, скажем, пару мегабайт или что-то в этом роде), а затем проанализировать его. Не пытайтесь получить только один или два байта для размера, а затем выполнить еще один прием после этого — это неэффективно, и вы все равно можете получить «короткие чтения», если отправленное сообщение было фрагментировано.