将protobuf从C ++发送到Java

时间:2015-06-12 01:09:36

标签: java c++ sockets protocol-buffers

我正在尝试通过套接字将C ++应用程序中的protobuf发送到Java应用程序。 我在mu C ++程序上使用一个简单的套接字来发送protobuf。在通过网络发送之前,我已将其序列化为char缓冲区。 在我的Java(服务器)程序中,我使用ServerSocket来接收数据。

我无法在Java端反序列化protobuf。它一直给我错误:

  1. 在解析协议消息时,输入意外地在字段中间结束。这可能意味着要么输入被截断,要么嵌入的消息误报了自己的长度。
  2. CodedInputStream遇到格式错误的varint。
  3. 我做错了什么?我的代码如下。

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

1 个答案:

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

应该这样做。