简体   繁体   English

Google Protocol Buffer(Java to C ++)

[英]Google Protocol Buffer (Java to C++)

I am attempting to setup a TCP/IP socket connection between Java and C++, with Java on Windows and C++ on a Raspberry Pi. 我试图在Java和C ++之间建立TCP / IP套接字连接,在Windows上使用Java,在Raspberry Pi上使用C ++。 The message being transmitted is a Google Protocol Buffer message, with a proto set as below: 正在传输的消息是Google Protocol Buffer消息,其原型设置如下:

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 code for Java (which acts as a client): 我有以下Java代码(充当客户端):

/* 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 as a server): 我有以下C ++代码(作为服务器):

//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 message, I am able to receive the appropriate number of bytes and values. 使用静态消息,我能够接收适当数量的字节和值。 With this, I moved to having values change dynamically on the Java side. 有了这个,我开始在Java端动态更改值。 However, it appears that on the c++ side, I will receive the correct number of bytes but the values will not have changed for a majority of the variables (only the first few). 但是,似乎在c ++方面,我将收到正确的字节数,但大多数变量(仅前几个)的值不会改变。 When I check the packaged and transmitted Google Protocol Buffer message on the Java side, it appears that I am sending the correct values. 当我在Java端检查打包和传输的Google协议缓冲区消息时,似乎我发送了正确的值。 Is there a better approach for receiving a Google Protocol Buffer message in c++? 有没有更好的方法来接收c ++中的Google Protocol Buffer消息?

Your biggest problem seems to be this: 你最大的问题似乎是:

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

When you construct a string like that - from a const char* - it will look for the first NUL as the terminator. 当你构造一个这样的string - 从const char* - 它将寻找第一个NUL作为终结符。 You should instead use... 你应该改用......

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

...which will ensure the entire chunk of received data is stored into the string. ...这将确保整个接收数据块存储在字符串中。

Another problem: 另一个问题:

  • read on a socket may return whatever's sent over multiple calls, so you should always adopt a convention for working out when to stop reading (eg a fixed number of bytes known to client and sender - perhaps from a structure size, or a sentinel character or sequence such as newline or NUL, or a fixed-sized length prefix) 在套接字上read可能会返回通过多个调用发送的任何内容,因此您应该始终采用约定来确定何时停止读取(例如,客户端和发送方已知的固定字节数 - 可能来自结构大小,或者标记字符或序列,如换行符或NUL,或固定大小的长度前缀)

    • this is a natural consequence of buffering over the stream: say your client app calls write / send thrice while the OS is too busy to actually get any of the data into a network packet: when it does do so it may be able to fit the first and half the second "write" into one packet, then send the rest of the second along with the third in another; 这是缓冲流的一个自然结果:假设您的客户端应用程序调用write / send三次,而操作系统太忙而无法将任何数据实际获取到网络数据包中:当它确实这样做时,它可能适合第一个和第二个半秒“写入”一个数据包,然后发送第二个的其余部分和第三个在另一个数据包中; if the receiver expects each read to read the start of a multi-byte logical message, they're in for a shock 如果接收器希望每次read读取多字节逻辑消息的开始,那么它们就会受到冲击

As for better approaches, for some small casual use I've found boost::asio makes for very concise, clear code and is a pleasure to use... lots of docs, examples, tutorials online. 至于更好的方法,对于一些小的随意使用我发现boost::asio使得非常简洁,清晰的代码,并且很高兴使用...许多文档,示例,在线教程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM