#c #network-programming #protocols
#c #сетевое программирование #протоколы
Вопрос:
Я разрабатываю сетевой протокол. У меня много неполиморфных структур. Мне нужно передать структуру ввода в пакет с его идентификатором (уникальным номером структуры) и сериализовать его в массив байтов для отправки. И десериализуйте ее так же: получите массив байтов, получите идентификатор структуры и десериализуйте байты как эту структуру.
Как?
Пример с комментариями:
// Internal structure, cannot be edited
struct FirstProcedureParams {
std::string some_string;
int some_integer;
};
// Also cannot be edited
struct SecondProcedureParams {
std::vector<int> some_vector;
std::map<int, int> some_map;
};
// My class to serialize and deserialize packet data to send to client or server.
class CallProcedurePacket : public BasePacket {
public:
void Serialize(uint8_t** bytes, size_t* length) override;
void Deserialize(const uint8_t* bytes, size_t length) override;
public:
int procedure_id; // for example, 1 - FirstProcedureParams, 2 - SecondProcedureParams.
// there is must be parameters for concrete procedure id.
};
void CallProcedurePacket::Serialize(uint8_t** bytes, size_t* length) {
// Some stuff..
writer.Write(procedure_id);
// How can I write dynamic parameters structure
// If it is not polymorphic and it hasn't method like Serialize?
// In this example only 2 structures: FirstProcedureParams and SecondProcedureParams.
// But in real code I have more than 15 structures.
}
void CallProcedurePacket::Deserialize(const uint8_t* bytes, size_t length) {
// Some stuff..
reader.Read(procedure_id);
// I need to get FirstProcedureParams if procedure_id equal 1
// or SecondProcedureParams if procedure_id equal 2.
}
// -----------------------------
// Example of using CallProcedurePacket:
void SomeSendFunction() {
FirstProcedureParams params;
params.some_string = "some string";
params.some_integer = 789;
CallProcedurePacket call_procedure_packet;
call_procedure_packet.procedure_id = 1;
call_procedure_packet.params = params; // what type should be `params` field? how can I write FirstProcedureParams to it?
SendPacket(call_procedure_packet);
}
void SomeSendFunction2() {
SecondProcedureParams params;
params.some_vector = { 1, 2, 3 };
params.some_map = {
{ 1, 5 },
{ 7, 9 }
};
CallProcedurePacket call_procedure_packet;
call_procedure_packet.procedure_id = 2;
call_procedure_packet.params = params; // params field should accept SecondProcedureParams too.
SendPacket(call_procedure_packet);
}
// And reading..
void SomeReceiveFunction() {
CallProcedurePacket call_procedure_packet = ReceivePacket();
if (call_procedure_packet.procedure_id == 1) {
FirstProcedureParams params;
// somehow get the params.
procedure(params.some_string, params.some_integer);
}
else if (call_procedure_packet.procedure_id == 2) {
SecondProcedureParams params;
// some usage of params.
}
}
Комментарии:
1. Вы более или менее заново изобретаете буферы протокола и, в частности, их
oneof
функции . Рассмотрите возможность использования protobufs вместо создания собственных.2. Вот простой способ выяснить, как это сделать, и он никогда не перестает работать. Просто достаньте чистый лист бумаги. Запишите, используя короткие простые предложения на простом английском языке, пошаговый процесс выполнения этого. Когда закончите, позвоните своей резиновой утке, чтобы договориться о встрече . Мы не пишем код для других людей в Stackoverflow. Мы всегда отсылаем такие вопросы к вашей резиновой утке. После того, как ваш резиновый утенок одобрит предложенный вами план действий, просто возьмите то, что вы записали, и переведите это непосредственно на C . Миссия выполнена!
3. Я думаю, вам следует прежде всего уточнить для себя, разрабатываете ли вы пользовательскую библиотеку сериализации или протокол связи, они разные , но имеют некоторые общие черты, например, требуют большого количества шаблонного кода. Вручную писать такой код — плохая идея, поэтому рекомендуется использовать различные генераторы кода. Если это сериализация, используйте protobuf или аналогичный. В случае, если это фактический протокол связи, используйте что-то вроде экосистемы CommsChampion