Мне нужно создать TCP-чат с клиентами C ++ и сервером Python (уже запущен), у меня есть сообщения в классе C ++, такие как
class Message{
public:
uint64 utc_time;
uint64 token;
string content;
};
Я отправляю это от клиента к серверу, на сервере у меня есть очередь с приоритетами по utc_time и мне нужно передать другим. У меня вопрос, как это сериализовать, какой формат использовать, чтобы избежать любых межъязыковых зависимостей от размера шрифта? (может быть, в будущем будет больше метаданных, так что нужно немного общего)? Кто-нибудь может дать мне совет, какой формат использовать для сериализации (или сбрасывать только как байты)?
class Persistent:
public:
Persistent(int sz):objSize(sz){}
void write(std::ostream& out)const{out.write((char*)this, objSize);}
void read(std::istream& in){in.read((char*)this, objSize);}
private:
int objSize;
};
Я подумал о другой возможности иметь десериализатор в c ++ на сервере и вызывать из python, если это возможно. Любое элегантное решение этой проблемы?
Если вы действительно хотите перейти на разные языки и кроссплатформенность, не беспокоясь о том, где заканчивается сообщение, взгляните на комбинацию Google Protobuf а также ZeroMQ.
При использовании обычных сокетов вы сначала должны прочитать размер сообщения (вы должны добавить это), а затем узнать, откуда и где массив байтов является полным сообщением.
Пример использования protobuf + zmq:
message Message {
optional uint64 utc_time = 1;
required uint64 token = 2;
optional string content = 3;
}
Используйте компилятор protobuf для генерации кода C ++ (или ruby / python / etc).
Чтобы использовать его в своем коде:
#include <Message.pb.h>
Message msg;
msg.set_token(1);
msg.set_content("Hello world");
Чтобы отправить его с помощью zmq:
std::string serialized = msg.SerializeAsString();
zmq::message_t reply(serialized.size());
memcpy(reply.data(), serialized.data(), serialized.size());
zmq_socket.send(reply);
Чтобы получить его с помощью zmq:
zmq::message_t request;
zmq_socket.recv(&request); // blocking
Message recv_msg;
recv_msg.ParseFromArray(request.data(), request.size());
Использование ZeroMQ — хорошее начало, так как оно берет на себя всю транспортную работу за вас. Лучший способ сериализации зависит от вида работы, которую вы делаете. Поскольку вы работаете с приложением чата, эффективность не имеет значения, поэтому я бы использовал текстовый формат с самоописанием, который проще всего отлаживать, отслеживать, регистрировать и использовать. Что-нибудь вроде protobufs или msgpack будет дополнительной работой без ощутимой награды. Вы можете использовать XML, JSON, заголовки в стиле HTTP, пары имя = значение и т. Д.
Когда вы начинаете создавать действительно большие объемы сообщений (сотни тысяч в секунду) или очень большие (более 1 Кбайт), вы можете начать думать о различных способах уменьшения размера сообщения. Я лично рекомендую придерживаться простейшего из возможных текстовых форматов, пока у вас не возникнет проблема с производительностью, а затем переключиться на наиболее эффективный двоичный формат для случаев, когда это необходимо. Но не в приложении чата …
Мне нравится использовать JSON, при условии, что у вас есть хороший буферизованный интерфейс для сокета и анализатор JSON на основе потоков. Хорошая вещь в JSON заключается в том, что вам не нужно указывать длину каждого сообщения. Правильно написанный JSON-анализатор может определить, когда он достигает конца «объекта». Таким образом, ваш объект чтения может просто анализировать JSON, когда он проходит по проводам, и когда вы достигнете конца исходного объекта, верните его в систему как одно сообщение.
Если JSON является избыточным для ваших данных, всегда есть простой текст. Большая часть интернета работает с открытым текстом (POP, IMAP, HTTP, FTP и т. Д.). И это потому, что простой текст — это самая простая вещь для использования кросс-платформенного / кросс-языкового.