C ++ поток байтов - PullRequest
       71

C ++ поток байтов

1 голос
/ 11 августа 2009

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

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

Ответы [ 3 ]

2 голосов
/ 11 августа 2009

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

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

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

0 голосов
/ 11 августа 2009

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

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

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

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

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

void SendData()
{
   char payload[256];

   Send(messageType)
   Send(payload)
}

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

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

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

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

MessageType
MessageSize
CRCCheckSum
MessageID
void buffer[payload]

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

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

  1. Для динамических данных отправляйте несколько пакетов, но со специальным флагом сказать, что больше данных должно прибыть, чтобы закончить это сообщение.
  2. Будьте проще, и если вы работаете с C ++, не принимайте пакет или данные будет содержать нулевой терминатор и проверить размер по сравнению с полезная нагрузка, если вы решите использовать нулевой терминатор.
0 голосов
/ 11 августа 2009

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

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

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

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

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

...