Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Нэглеподобная проблема

Автор вопроса: EliОтветов: 2

поэтому у меня есть эта игра в реальном времени с сервером C++ с отключенным nagle, использующим библиотеку SFML, и клиент использование asyncsocket также отключает nagle. Я отправляю 30 пакетов каждую 1 секунду. Нет проблем с отправкой от клиента к серверу, но при отправке с сервера к клиентам некоторые пакеты мигрируют. Например, если я отправляю "a" и "b" в совершенно разных пакетах, клиент читает это как "ab". Это случается только один раз, но это создает настоящую проблему в игре.

И что я должен делать? Как я могу это решить? Может что-то в сервере? Может настройки ОС?

Чтобы было ясно: я НЕ использую nagle, но у меня все еще есть эта проблема. Я отключил и в клиенте, и в сервере.

tcpreal-timenetwork-programmingsfmlasyncsocket

Ответы

Ответ 1 · рейтинг 1 · cnicutar

Вы должны отключить Nagle на обоих узлах. Возможно, вы захотите найти другой протокол, основанный на записи, например SCTP.

Редактировать2

Поскольку вы просите протокол, вот как я это сделаю:

  • Определите заголовок для сообщения. Допустим, я бы выбрал 32-битный заголовок.

    Header:
        MSG Length: 16b
        Version: 8b
        Type: 8b
    
  • Затем приходит настоящее сообщение, имеющее MSG Length байта.

Итак, теперь, когда у меня есть формат, как мне поступить?

Сервер

Когда я пишу сообщение, я добавляю контрольную информацию (на самом деле длина является наиболее важной) и отправляю все это целиком. Включение NODELAY или нет не имеет значения.

Клиент

Я постоянно получаю данные с сервера, верно? Так что я должен сделать что-то вроде read.

  • Чтение байтов с сервера. Любая сумма может прийти. Продолжайте читать, пока не получите хотя бы 4 байта.
  • Получив эти 4 байта, интерпретируйте их как заголовок и извлеките MSG Length
  • Продолжайте читать, пока не получите хотя бы MSG Length байт. Теперь вы получили сообщение и можете его обработать.

Это работает независимо от параметров TCP (таких как NODELAY), ограничений MTU и т. д.

Ответ 2 · рейтинг 3 · Robᵩ

Например, если я отправляю "a" и "b" в совершенно разных пакетах, клиент читает это как "ab". Это случается только один раз, но это создает настоящую проблему в игре.

Я думаю, вы упустили из виду фундаментальную природу TCP: это потоковый протокол, а не пакетный. TCP не учитывает и не сохраняет границы данных отправителя. Иными словами, TCP может объединять (или разделять!) "пакеты", которые вы отправляете, и представлять их получателю так, как он хочет. Единственное ограничение, которое соблюдает TCP, заключается в следующем: если байт доставлен, он будет доставлен в том же порядке, в котором он был отправлен. (И ничто в Нэгле не меняет этого.)

Итак, если вы дважды вызываете send (или write) на сервере, отправляя эти шесть байтов:

"packet" 1: A B C
"packet" 2: D E F

Ваша клиентская сторона может recv (или read) любую из этих последовательностей байтов:

ABC / DEF
ABCDEF
AB / CD / EF

Если вашему приложению требуется знание границ между writes отправителя, то вы несете ответственность за сохранение и передачу этой информации.

Как уже говорили другие, есть много способов сделать это. Например, вы можете отправлять новую строку после каждого кванта информации. Так (частично) работают HTTP, FTP и SMTP.

Вы можете отправить длину пакета вместе с данными. Обобщенная форма для этого называется TLV, что означает "Тип, длина, значение". Отправьте поле типа фиксированной длины, поле фиксированной длины, а затем значение произвольной длины. Таким образом, вы узнаете, когда прочитали все значение и готовы к следующему TLV.

Вы можете сделать так, чтобы каждый отправляемый вами пакет был идентичен по длине.

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы