Google 协议缓冲区(Java 到 C++)
Google Protocol Buffer (Java to C++)
我正在尝试在 Java 和 C++ 之间设置一个 TCP/IP 套接字连接,Java 在 Windows 上,C++ 在 Raspberry Pi 上。正在传输的消息是 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;
}
我有以下 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());
我有以下 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);
使用静态消息,我能够接收到适当数量的字节和值。有了这个,我开始在 Java 端动态更改值。然而,在 C++ 方面,我会收到正确的字节数,但大多数变量(只有前几个)的值不会改变。当我在 Java 端检查打包和传输的 Google Protocol Buffer 消息时,我似乎发送了正确的值。在 C++ 中接收 Google Protocol Buffer 消息是否有更好的方法?
你最大的问题好像是这个:
std::string inputStr = std::string(buffer);
当您从 const char*
构造一个这样的 string
时,它会寻找第一个 NUL 作为终止符。您应该改为使用...
std::string inputStr = std::string(buffer, n);
...这将确保接收到的数据的整个块都存储到字符串中。
另一个问题:
套接字上的 read
可能 return 通过多次调用发送的任何内容,因此您应该始终采用约定来确定何时停止读取(例如,固定数量的客户端和发送方已知的字节 - 可能来自结构大小,或标记字符或序列(如换行符或 NUL,或固定大小的长度前缀)
- 这是缓冲流的自然结果:假设您的客户端应用程序调用
write
/send
三次,而 OS 太忙而无法实际获取任何数据进入网络数据包:当它这样做时,它可能能够将第一个和第二个 "write" 的一半放入一个数据包中,然后将第二个的其余部分与第三个一起发送到另一个数据包中;如果接收方希望每个 read
读取多字节逻辑消息的开头,他们会感到震惊
至于更好的方法,对于一些小的随意使用,我发现 boost::asio
代码非常简洁、清晰,使用起来很愉快……有很多在线文档、示例和教程。
我正在尝试在 Java 和 C++ 之间设置一个 TCP/IP 套接字连接,Java 在 Windows 上,C++ 在 Raspberry Pi 上。正在传输的消息是 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;
}
我有以下 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());
我有以下 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);
使用静态消息,我能够接收到适当数量的字节和值。有了这个,我开始在 Java 端动态更改值。然而,在 C++ 方面,我会收到正确的字节数,但大多数变量(只有前几个)的值不会改变。当我在 Java 端检查打包和传输的 Google Protocol Buffer 消息时,我似乎发送了正确的值。在 C++ 中接收 Google Protocol Buffer 消息是否有更好的方法?
你最大的问题好像是这个:
std::string inputStr = std::string(buffer);
当您从 const char*
构造一个这样的 string
时,它会寻找第一个 NUL 作为终止符。您应该改为使用...
std::string inputStr = std::string(buffer, n);
...这将确保接收到的数据的整个块都存储到字符串中。
另一个问题:
-
套接字上的
read
可能 return 通过多次调用发送的任何内容,因此您应该始终采用约定来确定何时停止读取(例如,固定数量的客户端和发送方已知的字节 - 可能来自结构大小,或标记字符或序列(如换行符或 NUL,或固定大小的长度前缀)- 这是缓冲流的自然结果:假设您的客户端应用程序调用
write
/send
三次,而 OS 太忙而无法实际获取任何数据进入网络数据包:当它这样做时,它可能能够将第一个和第二个 "write" 的一半放入一个数据包中,然后将第二个的其余部分与第三个一起发送到另一个数据包中;如果接收方希望每个read
读取多字节逻辑消息的开头,他们会感到震惊
- 这是缓冲流的自然结果:假设您的客户端应用程序调用
至于更好的方法,对于一些小的随意使用,我发现 boost::asio
代码非常简洁、清晰,使用起来很愉快……有很多在线文档、示例和教程。