Reputation: 4177
I am trying to send a protobuf from a C++ application to a Java application via a socket. I am using a simple socket on mu C++ program to send the protobuf. I have serialized it to a char buffer before I send it via the network. On my Java(server) program, I use a ServerSocket to receive the data.
I have trouble de-serializing the protobuf on the Java side. It keeps giving me errors:
What am I doing wrong? My code is below.
The protobuf example is taken from Google's tutorial - AddressBook.proto tutorial
C++ code:
#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 Program:
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();}
}
}
Upvotes: 3
Views: 6530
Reputation: 33932
OK. I read the documentation.
int size = address_book.ByteSize();
char * buffer = new char[size];
address_book.SerializeToArray(buffer, size);
Builds the message complete with the size of the message. The message is not a string. It is a packed mess of whatever it takes to get the message as small as possible.
iResult = send(ConnectSocket, buffer, (int)strlen(buffer), 0);
Will send the message up to the first null embedded in buffer or after buffer if buffer does not contain any nulls. You will very likely send either too much or too little.
Fortunately you already know the size of the message: size
.
iResult = send(ConnectSocket, buffer, size, 0);
Should do it.
Upvotes: 5