Serialize o objeto C ++ para enviar via sockets para Python - a melhor abordage
Preciso criar uma comunicação de rede entre duas estruturas diferentes, uma escrita emC++
e o outro emPython
.
Para trocar dados, quero criar algum tipo de estrutura flexível (basicamente uma estrutura) noC++
, que é serializado, enviado através de soquetes paraPython
e depois desserializado.
Qual é a maneira mais comum de fazer isso? Tenho certeza queBoost
poderia fazê-lo em ambos os lados, uma vez que existeboost python
, mas não quero exagerar muito nos requisitos do projeto. Então, talvez exista uma biblioteca menor ou qualquer outra solução elegante, exceto a especificação de um próprio formato de dados binários?
ATUALIZAR
Então, aqui está um exemplo de como usar o Googleprotobuf
para enviar uma estrutura de dados de umC++
script para umPython
script viaUDP
. Isso foi testado no Mac OS X Mavericks, mas também deve funcionar bem em outros sistemas Uni
Installing protobuf
O primeiro passo é instalar oprotobuf
library. Eu usei homebrew para a biblioteca principal epip
para instalar oPython
modules:
brew install protobuf
pip install protobuf
Em seguida, defini uma estrutura de dados muito simples usando a proto-sintaxe:
Filename: foo.proto
package prototest;
message Foo {
required int32 id = 1;
required string bar = 2;
optional string baz = 3;
}
Este proto-arquivo agora pode ser traduzido para as classes C ++ e Python via:
protoc foo.proto --cpp_out=. --python_out=.
A pasta agora deve conter o cabeçalho C ++ e os arquivos de origem e o código Python:
├── foo.pb.cc
├── foo.pb.h
├── foo.proto
└── foo_pb2.py
Vamos dar uma olhada no muito básicoC++
, que serve para enviar uma instância defoo
pela rede, usando UDP (para host local na porta 5555):
Nome do arquivo: 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;
}
Eu compilei viaclang++
:
clang++ -o send send.cc foo.pb.cc -lprotobuf
E finalmente, este é oPython
ódigo @, que aguarda pacotes UDP e desserializa-os parafoo
. Novamente: nenhuma verificação de erro, apenas para demonstrar a funcionalidade:
Filename: 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))
Agora terminamos e esta é a estrutura final do diretório:
├── foo.pb.cc
├── foo.pb.h
├── foo.proto
├── foo_pb2.py
├── receive.py
├── send
└── send.cc
Para testar o script, basta executarreceive.py
para ouvir pacotes UDP via
python receive.py
e fique de olho na saída quando executar o C ++ geradosend
roteiro
./send