Protocole Buffer over socket en C ++

J’essaie d’explorer Protocol Buffer (PB) sur la plate-forme Linux et mon langage de codage est C ++. J’ai trouvé des exemples dans la documentation en ligne du tampon de protocole mais rien de spécifique à l’envoi et à la réception de socket (ou je l’ai complètement manqué :)). J’ai donc décidé d’append le message Longueur avant le message réel et de l’envoyer via socket. J’apprécierais que quelqu’un puisse suggérer une meilleure solution que ce que je compte faire et y a-t-il quelque chose de prêt dans PB pour créer de tels paquets.

Mais je me retrouve toujours avec un problème côté serveur où je dois décoder le paquet. Dites si le client envoie un paquet de 10 octets dans lequel le premier octet correspond à la longueur du paquet; Mais il est impossible de connaître la longueur avant de décoder le paquet. Donc, même si je lis les 4 premiers octets, comment en déduire la valeur avec un demi-paquet de lecture en utilisant Protocol Buffer.

Enfin, je pourrais le faire fonctionner. Je publie le code ici pour pouvoir le revoir et le commenter, et si quelqu’un veut l’implémenter en c ++, ce morceau de code peut aider. C’est un code minable, mon intention était de faire fonctionner Protobuf de manière préfixée en longueur. J’ai pris le code du serveur client depuis un site dont je ne me souviens plus et je l’ai modifié pour prendre en charge protobuf. Ici, le serveur jette d’abord un coup d’oeil dans le socket et obtient la longueur du paquet total, puis la lecture du socket est effectuée pour lire le paquet entier. Il peut y avoir mille façons de le faire, mais pour une solution rapide, je l’ai fait de cette manière. Mais je dois trouver un meilleur moyen d’éviter les 2 recv par paquet, mais dans ma condition, tous les messages sont de taille différente, c’est donc la seule façon de deviner.

Fichier proto

message log_packet { required fixed64 log_time =1; required fixed32 log_micro_sec =2; required fixed32 sequence_no =3; required fixed32 shm_app_id =4; required ssortingng packet_id =5; required ssortingng log_level=6; required ssortingng log_msg=7; } 

Tampon de protocole Code client

 #include  #include "message.pb.h" #include  #include  #include  #include  #include  #include  using namespace google::protobuf::io; using namespace std; int main(int argv, char** argc){ /* Coded output stram */ log_packet payload ; payload.set_log_time(10); payload.set_log_micro_sec(10); payload.set_sequence_no(1); payload.set_shm_app_id(101); payload.set_packet_id("TST"); payload.set_log_level("DEBUG"); payload.set_log_msg("What shall we say then"); cout<<"size after serilizing is "<WriteVarint32(payload.ByteSize()); payload.SerializeToCodedStream(coded_output); int host_port= 1101; char* host_name="127.0.0.1"; struct sockaddr_in my_addr; char buffer[1024]; int bytecount; int buffer_len=0; int hsock; int * p_int; int err; hsock = socket(AF_INET, SOCK_STREAM, 0); if(hsock == -1){ printf("Error initializing socket %d\n",errno); goto FINISH; } p_int = (int*)malloc(sizeof(int)); *p_int = 1; if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )|| (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){ printf("Error setting options %d\n",errno); free(p_int); goto FINISH; } free(p_int); my_addr.sin_family = AF_INET ; my_addr.sin_port = htons(host_port); memset(&(my_addr.sin_zero), 0, 8); my_addr.sin_addr.s_addr = inet_addr(host_name); if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){ if((err = errno) != EINPROGRESS){ fprintf(stderr, "Error connecting socket %d\n", errno); goto FINISH; } } for (int i =0;i<10000;i++){ for (int j = 0 ;j<10;j++) { if( (bytecount=send(hsock, (void *) pkt,siz,0))== -1 ) { fprintf(stderr, "Error sending data %d\n", errno); goto FINISH; } printf("Sent bytes %d\n", bytecount); usleep(1); } } delete pkt; FINISH: close(hsock); } 

Tampon de protocole code serveur

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include "message.pb.h" #include  #include  #include  using namespace std; using namespace google::protobuf::io; void* SocketHandler(void*); int main(int argv, char** argc){ int host_port= 1101; struct sockaddr_in my_addr; int hsock; int * p_int ; int err; socklen_t addr_size = 0; int* csock; sockaddr_in sadr; pthread_t thread_id=0; hsock = socket(AF_INET, SOCK_STREAM, 0); if(hsock == -1){ printf("Error initializing socket %d\n", errno); goto FINISH; } p_int = (int*)malloc(sizeof(int)); *p_int = 1; if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )|| (setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){ printf("Error setting options %d\n", errno); free(p_int); goto FINISH; } free(p_int); my_addr.sin_family = AF_INET ; my_addr.sin_port = htons(host_port); memset(&(my_addr.sin_zero), 0, 8); my_addr.sin_addr.s_addr = INADDR_ANY ; if( bind( hsock, (sockaddr*)&my_addr, sizeof(my_addr)) == -1 ){ fprintf(stderr,"Error binding to socket, make sure nothing else is listening on this port %d\n",errno); goto FINISH; } if(listen( hsock, 10) == -1 ){ fprintf(stderr, "Error listening %d\n",errno); goto FINISH; } //Now lets do the server stuff addr_size = sizeof(sockaddr_in); while(true){ printf("waiting for a connection\n"); csock = (int*)malloc(sizeof(int)); if((*csock = accept( hsock, (sockaddr*)&sadr, &addr_size))!= -1){ printf("---------------------\nReceived connection from %s\n",inet_ntoa(sadr.sin_addr)); pthread_create(&thread_id,0,&SocketHandler, (void*)csock ); pthread_detach(thread_id); } else{ fprintf(stderr, "Error accepting %d\n", errno); } } FINISH: ;//oops } google::protobuf::uint32 readHdr(char *buf) { google::protobuf::uint32 size; google::protobuf::io::ArrayInputStream ais(buf,4); CodedInputStream coded_input(&ais); coded_input.ReadVarint32(&size);//Decode the HDR and get the size cout<<"size of payload is "< 

Malheureusement, protobuf ne permet pas de “conditionner” (délimiter) vos messages:

Si vous souhaitez écrire plusieurs messages dans un seul fichier ou stream, il vous appartient de suivre l’endroit où un message se termine et le suivant commence. Le format de fil du tampon de protocole n’est pas auto-délimité, de sorte que les parsingurs de tampon de protocole ne peuvent pas déterminer où se termine le message par eux-mêmes. Le moyen le plus simple de résoudre ce problème consiste à écrire la taille de chaque message avant d’écrire le message lui-même.

(de leur documentation )

Donc, ils recommandent essentiellement la même solution que vous avez trouvée.