2015-06-12 5 views
3

Я пытаюсь отправить protobuf из приложения C++ в приложение Java через сокет. Я использую простой сокет в программе mu C++ для отправки protobuf. Я передал его в буфере символов, прежде чем отправлять его по сети. В моей программе Java (сервер) я использую ServerSocket для получения данных.Отправка protobuf из C++ в Java

У меня возникла проблема де-сериализации protobuf на стороне Java. Он продолжает давать мне ошибки:

  1. При анализе сообщения протокола вход неожиданно заканчивается посередине поля. Это может означать, что вход был усечен или что встроенное сообщение неправильно сообщило о своей собственной длине.
  2. CodedInputStream столкнулся с неправильной вариацией.

Что я делаю неправильно? Мой код ниже.

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

Помогла ли вам решить эту проблему с помощью нижеприведенного решения? Becuase я попытался воспроизвести вашу реализацию, но это не сработало для меня, клиент продолжает получать «InvalidProtocolBufferException: при разборе сообщения о протоколе вход неожиданно завершается посередине поля», используя библиотеки protobuf3 ... – Hayra

ответ

3

OK. Я прочитал документацию.

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); 

Должно сделать это.

+0

Работал! большое спасибо ! – chrisrhyno2003

Смежные вопросы