我正在尝试通过套接字将C ++应用程序中的protobuf发送到Java应用程序。 我在mu C ++程序上使用一个简单的套接字来发送protobuf。在通过网络发送之前,我已将其序列化为char缓冲区。 在我的Java(服务器)程序中,我使用ServerSocket来接收数据。
我无法在Java端反序列化protobuf。它一直给我错误:
我做错了什么?我的代码如下。
protobuf示例来自Google的教程 - AddressBook.proto教程
C ++代码:
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <fstream>
#include <string>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include<conio.h>
#include "addressbook.pb.h"
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phone();
phone_number->set_number(number);
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
}
else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
}
else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
}
else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
tutorial::AddressBook address_book;
// Add an address.
PromptForAddress(address_book.add_person());
{
int size = address_book.ByteSize();
char * buffer = new char[size];
address_book.SerializeToArray(buffer, size);
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("localhost", "5000", &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
{
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
// Connect to server.
iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
freeaddrinfo(result);
// Send an initial buffer
iResult = send(ConnectSocket, buffer, (int)strlen(buffer), 0);
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
_getch();
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
}
}
Java程序:
package networkmonitor;
import com.example.tutorial.AddressBookProtos.AddressBook;
import com.example.tutorial.AddressBookProtos.Person;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.Parser;
import java.io.IOException;
import java.io.InputStream;
import static java.lang.System.in;
import java.net.ServerSocket;
import java.net.Socket;
class NetworkMonitor {
// Iterates though all people in the AddressBook and prints info about them.
static void Print(AddressBook addressBook) {
for (Person person: addressBook.getPersonList()) {
System.out.println("Person ID: " + person.getId());
System.out.println(" Name: " + person.getName());
if (person.hasEmail()) {
System.out.println(" E-mail address: " + person.getEmail());
}
for (Person.PhoneNumber phoneNumber : person.getPhoneList()) {
switch (phoneNumber.getType()) {
case MOBILE:
System.out.print(" Mobile phone #: ");
break;
case HOME:
System.out.print(" Home phone #: ");
break;
case WORK:
System.out.print(" Work phone #: ");
break;
}
System.out.println(phoneNumber.getNumber());
}
}
}
// Main function: Reads the entire address book from a file and prints all
// the information inside.
public static void main(String[] args) throws Exception {
ServerSocket server = null;
try
{
server = new ServerSocket(5000);
}
catch (IOException e)
{
System.out.println("Error on port: 5000 " + ", " + e);
System.exit(1);
}
System.out.println("Server setup and waiting for client connection ...");
Socket client = null;
try
{
client = server.accept();
}
catch (IOException e)
{
System.out.println("Did not accept connection: " + e);
System.exit(1);
}
System.out.println("Client connection accepted. Moving to local port ...");
try
{
InputStream inStream = client.getInputStream();
AddressBook addressBook = AddressBook.parseDelimitedFrom(inStream);
Print(addressBook);
in.close();
client.close();
server.close();
}
catch(IOException e)
{ System.out.println("IO Error in streams " + e);
e.printStackTrace();}
}
}
答案 0 :(得分:3)
行。我阅读了文档。
int size = address_book.ByteSize();
char * buffer = new char[size];
address_book.SerializeToArray(buffer, size);
使用邮件大小构建完整的邮件。消息不是字符串。无论如何使消息尽可能小,这都是一团糟。
iResult = send(ConnectSocket, buffer, (int)strlen(buffer), 0);
如果缓冲区不包含任何空值,则将消息发送到嵌入缓冲区或缓冲区之后的第一个空值。你很可能会发送太多或太少。
幸运的是,您已经知道邮件的大小:size
。
iResult = send(ConnectSocket, buffer, size, 0);
应该这样做。