Google Protocol Buffer (Java to C ++)

I am trying to establish a TCP / IP socket connection between Java and C ++, with Java on Windows and C ++ on a Raspberry Pi. The message being passed is a google protocol buffer message, with the protocol set below:

package package_name;

message Win2Pi{
    optional int32 num1= 1;
    optional int32 num2= 2;
    optional int32 num3= 3;
    optional int32 num4= 4;
    optional bool logic1= 5;
    optional bool logic2= 6;
    optional bool logic3= 7;
    optional bool logic4= 8;
    optional bool logic5= 9;
    optional int32 num5= 10;
    optional bool logic6= 11;
}

      

I have the following Java code (which acts as a client):

/* Java Code to Open Socket, Create Protobuf Message, and Send */
Socket clientSocket = new Socket(hostName, portNumber);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
WinToPi.Builder w2p = WinToPi.newBuilder();
w2p.setNum1(255);
w2p.setNum2(255);
w2p.setNum3(255);
w2p.setNum4(255);
w2p.setLogic1(true);
w2p.setLogic2(true);
w2p.setLogic3(true);
w2p.setLogic4(true);
w2p.setLogic5(false);
w2p.setNum5(7);
w2p.setLogic6(true);
w2p.build().writeTo(clientSocket.getOutputStream());

      

I have the following code for C ++ (which acts like a server):

//Protobuf Setup Variables
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[1024];
struct sockaddr_in serv_addr, cli_addr;
int n;

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){ 
    std::cout << "Error Opening Socket!" << std::endl;
    exit(1); //error
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){ 
    std::cout << "Error on Binding!" << std::endl; ;
    exit(1); //error
}

listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
    std::cout << "ERROR on accept" << std::endl;
    exit(1);
}

/* Clear Buffer and Read Message from Client */
bzero(buffer,1024);
n = read(newsockfd,buffer,1023);

std::cout << "n: " << n << std::endl;

if (n < 0){ 
    std::cout << "Error Reading From Socket!" << std::endl;
}

/* Translate Shoreside to Pi Message */
std::string inputStr = std::string(buffer);
package_name::WinToPi w2p;
w2p.ParseFromString(inputStr);

      

With a static post, I can get the corresponding number of bytes and values. With that, I moved on to making the values ​​change dynamically on the Java side. However, it looks like on the C ++ side I am getting the correct number of bytes, but the values ​​will not change for most of the variables (only the first few). When I inspect the packed and passed google protocol buffer message on the Java side, it seems that I am sending the correct values. Is there a better way to get the google protocol buffer message in C ++?

+3


source to share


1 answer


The biggest problem is this:

std::string inputStr = std::string(buffer);

      

When you build string

like this - from const char*

- it will look for the first NUL as a terminator. Instead, you should use ...

std::string inputStr = std::string(buffer, n);

      



..., which ensures that the entire chunk of received data is stored in a string.

Another problem:

  • read

    on a socket can return all dispatched across multiple calls, so you should always accept a development convention for when to stop reading (for example, a fixed number of bytes known to the client and sender - perhaps from the size of a structure or a sentinel character or sequence such as newline or NUL , or fixed length prefix)

    • This is a natural consequence of stream buffering: let's say your client application calls write

      / send

      three times, while the OS is too busy to actually get any of the data into the network packet: when it does, it might match the first and half of the second "write" in one packet, and then send the rest of the second along with the third to another; if the recipient expects everyone to read

      read the beginning of a multibyte logical message, they will be in shock.

As for the best approaches, for a little random use I found boost::asio

makes for very concise, clear code and happy to use ... lots of docs, examples, tutorials online.

0


source







All Articles