简体   繁体   English

将protobuf从C ++发送到Java

[英]Sending protobuf from C++ to Java

I am trying to send a protobuf from a C++ application to a Java application via a socket. 我试图通过套接字从C ++应用程序发送一个protobuf到Java应用程序。 I am using a simple socket on mu C++ program to send the protobuf. 我在mu C ++程序上使用一个简单的套接字来发送protobuf。 I have serialized it to a char buffer before I send it via the network. 在通过网络发送之前,我已将其序列化为char缓冲区。 On my Java(server) program, I use a ServerSocket to receive the data. 在我的Java(服务器)程序中,我使用ServerSocket来接收数据。

I have trouble de-serializing the protobuf on the Java side. 我无法在Java端反序列化protobuf。 It keeps giving me errors: 它一直给我错误:

  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. CodedInputStream遇到格式错误的varint。

What am I doing wrong? 我究竟做错了什么? My code is below. 我的代码如下。

The protobuf example is taken from Google's tutorial - AddressBook.proto tutorial protobuf示例来自Google的教程 - AddressBook.proto教程

C++ code: 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 Program: 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();}
    }
}

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 . 幸运的是,您已经知道消息的大小: size

iResult = send(ConnectSocket, buffer, size, 0);

Should do it. 应该这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM