Вопрос

Для сетевого приложения способ, которым мы передаем динамические данные, заключается в запоминании структуры в a (void*).Это создает некоторые проблемы, например, когда это делается с std::string .Строки могут иметь динамическую длину, так как же другая сторона узнает, когда строка заканчивается?Идея, которая у меня возникла, состояла в том, чтобы использовать что-то похожее на DataOuputStream Java, где я мог бы просто передавать в него любые переменные, а затем их можно было бы поместить в (void *).Если это невозможно сделать, тогда это круто.Мне просто не очень нравится запоминать структуру.Что-то в этом кажется не совсем правильным.

Спасибо,
Робби

Это было полезно?

Решение

нет ничего плохого в использовании memcpy в структуре - поскольку длина структуры заполнена буферами фиксированного размера.Поместите туда динамическую переменную, и вам придется сериализовать ее по-другому.

Если у вас есть структура с std::strings, создайте оператор потока и используйте его для форматирования буфера.Затем вы можете записать этот буфер в транспорт данных.Если у вас есть ускорение, используйте Повышение::сериализовать который делает все это за вас (эта ссылка также содержит ссылки на альтернативные библиотеки сериализации)

Примечания:Обычный способ передачи буфера переменного размера — начать с отправки длины, а затем такого же количества байтов данных.Иногда вы видите, что данные передаются до тех пор, пока не будет получен разделитель (и поля внутри этих данных сами разделяются другим символом, например запятой).

Другие советы

Я вижу две части этого вопроса:- Сериализация данных по сети - как передавать структуры в стек сети

Для сериализации данных по сети вам понадобится протокол.Не должно быть сложно;для ASCII может подойти даже cr/lf в качестве конца пакета.Если вы используете платформу (например, MFC), она может предоставить вам функции сериализации;в этом случае вам нужно беспокоиться о том, как отправить это в пакетах.Пакетизация, которая часто работает хорошо для меня:

<length><data_type>[data....][checksum]

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

Если вы работаете над memcpy со структурами, вам нужно учитывать, что memcpy создает только поверхностную копию.Указатель бесполезен после передачи по сети;Предположим, вы должны передать данные из этого указателя (т.е.содержимое вашего примера строки)

Для отправки динамических данных по сети у вас есть следующие опции.

Первый вариант в том же пакете.

void SendData()
{
   int size;
   char payload[256];

   Send(messageType)
   Send(size);
   Send(payload)
}

Второй вариант:

void SendData()
{
   char payload[256];

   Send(messageType)
   Send(payload)
}

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

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

Хотя, я думаю, ни один из вариантов не охватывает полностью проблему, с которой вы столкнулись.Во-первых, вам нужно определить, если вы создаете игру, какой тип протокола вы будете использовать, UDP?TCP?Вторая проблема, с которой вы столкнетесь, - это максимальный размер пакета.Затем, вдобавок ко всему, вам нужно иметь готовую структуру, чтобы вы могли рассчитать оптимальный размер пакета, который не будет фрагментирован и потерян для интернета.После этого у вас есть контроль пропускной способности в отношении того, сколько данных вы можете передавать и получать между клиентом и сервером.

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

MessageType
MessageSize
CRCCheckSum
MessageID
void buffer[payload]

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

Итак, в заключение.

  1. Для динамических данных отправьте несколько пакетов, но со специальным флагом сказать, что для завершения этого сообщения должно поступить больше данных.
  2. Сделайте это простым, и если вы работаете с C ++, не предполагайте, что пакет или данные будут содержать нулевой ограничитель и проверьте размер по сравнению с полезной нагрузкой, если вы решите использовать нулевой ограничитель.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top