Sending protobuf from C++ to Java - Unable to parse in java

358 views
Skip to first unread message

Ashwin Venkataraman

unread,
Jun 11, 2015, 9:08:33 PM6/11/15
to prot...@googlegroups.com
   I am sending a protobuf from a C++ program to a java program via sockets. I am unable to deserialize the proto in the Java program .I keep encountering errors like :

1. While parsing a protocol message, the input ended unexpectedly in the middle of a field.  This could mean either than the input has been truncated or that an embedded message misreported its own length.
2. CodedInputStream encountered a malformed varint

I am using a simple socket in C++ and a ServerSocket in the java program. I an serializing my proto to a char* buffer before I sent it to the socket. what am I doing wrong? Kindly help.

I have both my code below:

P.S - the example for proto is taken from the Google example - AddressBook.proto

C++ code: ( Client side - sends data )
#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 code - Server side - receives data
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
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();}
  }
}

肖锋

unread,
Jun 12, 2015, 2:25:44 AM6/12/15
to prot...@googlegroups.com
Java's parseDelimitedFrom() method expects a length prefix before the content of the message. In C++, you will need to add this prefix using CodedOutputStream:

CodedOutputStream coded_output(...);
int length = message.ByteSize();
coded_output.WriteVarint32(length);
message.SerializeToCodedStream(&coded_output);
Reply all
Reply to author
Forward
0 new messages