Ответ 1
Взгляните на буферы протокола Google http://code.google.com/apis/protocolbuffers/ как альтернатива упрощенной сериализации.
Скажем, у меня есть структура:
struct person
{
char name[10];
int age;
};
struct car
{
int locationX;
int locationY;
};
struct company
{
vector<person> employees;
vector<car> cars;
};
Например, я хочу send/recv
целое company
использовать сокет (UDP). Итак, отправьте и верните один раз.
Как я могу это сделать? Не могли бы вы дать мне какой-то код sinppet? Как отправить все и прочитать все.
Спасибо!
Взгляните на буферы протокола Google http://code.google.com/apis/protocolbuffers/ как альтернатива упрощенной сериализации.
В формулировке вашего вопроса предполагается, что вы ищете следующее:
company foo;
send(sockfd, &foo, sizeof(foo), 0); // DO NOT do this
В основном это сбрасывает всю память структуры company
в ваш сокет. Этот НЕ РАБОТАЕТ в этом случае. И даже когда это работает, это действительно плохая идея. Причина, по которой он не будет работать, заключается в том, что vector
не содержит данные напрямую. Они указывают на это. Это означает, что когда вы выгружаете структуру, содержащую векторы, в сокет, вы будете указывать указатели на память, но не на то, что указано. Это приведет к (в лучшем случае) сбоям на принимающей стороне.
Это будет работать для отдельных объектов person
или car
. Они не содержат указателей, поэтому их память содержит все соответствующие значения
На стороне отправки:
person joe = { "Joe", 35 };
send(sockfd, &joe, sizeof(joe), 0); // may work, but is a bad idea, see below
На принимающей стороне:
person joe;
recv(sockfd, &joe, sizeof(joe), 0);
Но это все еще плохая идея. Он полагается на сторону отправки и принимающую сторону, имеющую ту же самую макет памяти для своих структур. Это может быть неверно по ряду причин. Некоторые из них включают один из чипов PowerPC, а другой - на чип Intel x86. Или один из них находится на компьютере Windows, скомпилированном с Visual Studio, а другой - на машине Linux, скомпилированной с помощью gcc. Или, возможно, кто-то изменил некоторые флагов компилятора, которые по-разному меняют структуру структуры по умолчанию. Любое количество причин.
На самом деле, вы должны использовать схему сериализации, как все здесь предложили. Я бы предложил буферы протокола Google или растровую структуру сериализации, с которой уже связаны другие люди. Но есть и другие.
Если вы хотите сделать много из них, вы можете посмотреть в "Трэйфте". Он автоматически сгенерирует весь необходимый код для сериализации всех структур для вас, поэтому вам не придется делать это вручную.
Они поддерживают строки слишком практично.
О! И это бесплатно. 8 -)
Другое дело, он отправляет двоичные данные как таковые, поэтому вам не придется преобразовывать числа в строки и наоборот. Это намного быстрее сделать, если большинство ваших данных не являются строками.
Использовать библиотеку сериализации Boost:
http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/index.html
Это, вероятно, самый надежный, универсальный, надежный, простой в использовании и даже кросс-платформенный способ для такой задачи.
Как уже говорили другие, использование какой-либо библиотеки сериализации обеспечит наиболее надежное (и, вероятно, самое простое в обслуживании) решение. Если, однако, вы действительно хотите реализовать все это самостоятельно, то следующее показывает "идею", как, возможно, приблизиться к ней. Следующий выделяет буфер, а затем заполняет его содержимым векторного персонала. Предполагается, что переменная c
имеет тип company
.
Некоторые примечания:
htonl
используется для хранения целочисленных значений в сетевом порядке байтов. Принимающая сторона должна использовать ntohl
для их считывания.Простой и очень неполный пример:
// allocate buffer to store all the data for a send. In a real world
// this would need to be broken up into appropriately sized chunks
// to avoid difficulties with UDP packet fragmentation.
// This likely over-allocates because the structure likely has padding
char *buf = new char[ sizeof( uint32_t ) + // for total number of entries
sizeof( person ) * c.employees.size() ]; // for each entry
char *pos = buf;
// Indicate how many are being sent
*(uint32_t*)pos = htonl( c.employees.size() );
pos += sizeof uint32_t;
for ( vector<person>::iterator pi = c.employees.begin();
pi != c.employees.end(); pi++ )
{
*(uint32_t*)pos = htonl( pi->age );
pos += sizeof uint32_t;
strcpy( pos, pi->name );
pos += strlen( pi->name ) + 1;
}
send( 0, buf, (int)( pos - buf ), 0 );
delete [] buf;
// The receiving end would then read the number of items and
// reconstruct the structure.