Трябва да създам мрежова комуникация между две различни рамки, едната написана на C++
, а другата на Python
.
За обмен на данни искам да създам някакъв вид гъвкава структура (основно структура) в C++
, която се сериализира, изпраща през сокети до Python
и след това се десериализира.
Кой е най-често срещаният начин за това? Сигурен съм, че Boost
може да го направи и от двете страни, тъй като има boost python
, но не искам да взривявам толкова много изискванията на проекта. И така, има ли може би по-малка библиотека или каквото и да е друго елегантно решение, освен посочване на собствен двоичен формат на данни?
АКТУАЛИЗАЦИЯ:
Ето един пример как да използвате Googles protobuf
за изпращане на структура от данни от C++
скрипт към Python
скрипт чрез UDP
. Това е тествано на Mac OS X Mavericks, но трябва да работи добре и на други Unix системи.
Инсталиране на protobuf
Първата стъпка, разбира се, е инсталирането на библиотеката protobuf
. Използвах homebrew за основната библиотека и pip
за инсталиране на Python
модулите:
brew install protobuf
pip install protobuf
След това дефинирах много проста структура от данни, използвайки протосинтаксиса:
Име на файл: foo.proto
package prototest;
message Foo {
required int32 id = 1;
required string bar = 2;
optional string baz = 3;
}
Този протофайл вече може да бъде преведен в C++ и Python класове чрез:
protoc foo.proto --cpp_out=. --python_out=.
Сега папката трябва да съдържа C++ заглавката и изходните файлове и кода на Python:
├── foo.pb.cc
├── foo.pb.h
├── foo.proto
└── foo_pb2.py
Нека да разгледаме основния C++
код, който е предназначен да изпрати екземпляр на foo
по мрежата, използвайки UDP (до localhost на порт 5555):
Име на файл: send.cc
#include <sys/socket.h>
#include <arpa/inet.h>
// this is our proto of foo
#include "foo.pb.h"
int main(int argc, char **argv)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
inet_aton("127.0.0.1", &addr.sin_addr);
addr.sin_port = htons(5555);
// initialise a foo and set some properties
GOOGLE_PROTOBUF_VERIFY_VERSION;
prototest::Foo foo;
foo.set_id(4);
foo.set_bar("narf");
// serialise to string, this one is obvious ; )
std::string buf;
foo.SerializeToString(&buf);
int sock = socket(PF_INET, SOCK_DGRAM, 0);
sendto(sock, buf.data(), buf.size(), 0, (struct sockaddr *)&addr, sizeof(addr));
return 0;
}
Компилирах го чрез clang++
:
clang++ -o send send.cc foo.pb.cc -lprotobuf
И накрая, това е кодът Python
, който чака UDP пакети и ги десериализира в foo
. Отново: никаква проверка за грешки, това е само за демонстрация на функционалността:
Име на файл: receive.py
import socket
from foo_pb2 import Foo
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1", 5555))
foo = Foo()
while True:
data, addr = sock.recvfrom(1024)
foo.ParseFromString(data)
print("Got foo with id={0} and bar={1}".format(foo.id, foo.bar))
Сега сме готови и това е окончателната структура на директорията:
├── foo.pb.cc
├── foo.pb.h
├── foo.proto
├── foo_pb2.py
├── receive.py
├── send
└── send.cc
За да тествате скрипта, просто стартирайте receive.py
, за да слушате UDP пакети чрез
python receive.py
и следете изхода, когато изпълнявате C++ генерирания send
скрипт:
./send