Send Google Protocol Buffer With ZeroMQ Across NetWork to Raspberry Pi
1. Overview
When we want to send message across network with fast respond, We know ZeroMQ
is one of the best choices. While sending across network and taking care of your message can be a big headache. Our own message can be hard to maintain with little flexibility. That’s where you need to consider a protocol to handler your growing messages. So now we use Google Protocol Buffer
which is free and efficient to handle our protocol.
Ubuntu PC ----ZeroMQ Message With Protocol Buffer----> Raspberry Pi
You can check out the entire project from my GitHub.
2. Installation
We need
- Qt Creator at Ubuntu PC
- Python at Raspberry Pi
- Both Ubuntu PC and Raspberry Pi are in same network
- Protocol Buffer Library at both Ubuntu PC and Raspberry Pi
- You can refer to this link for installation of Protocol Buffer
- You can refer to this link to install Python version of ZeroMQ
- You can refer to this link to install C++ version of ZeroMQ
Note: Installation instructions can be applied to both Ubuntu and Raspberry Pi. They are basically same since they are both *nix system.
3. Implementation
Since the project is hosted on GitHub, I will just explain necessary implementation.
3.1 Both System
In order to exchange message between Ubuntu and Raspberry, Both system must have protocol message file (.proto
) in their own system.
We will decipher the following message protocol as followed. We will be sending as message
as addressBook
. In the adressBook, there can be many Person
as signified by repeated
keyword. Similarly, Person must have name
as indicated by required
and email
is optional for a Person since the keyword is optional
. The " = 1", " = 2" markers on each element identify the unique tag
that field uses in the binary encoding.
package message;
message Person {
required string name = 1;
optional string email = 2;
}
message AddressBook{
repeated Person person = 1;
}
Note:
.proto
file must be compiled before it can be used in the program. You can looked how it can be compiled at.pro
file andpython
in the project.
You can manually compile the .proto file also. Just use
For Python
protoc message.proto --python_out='.'
For C++
protoc message.proto --cpp_out='.'
3.2 Raspberry Pi
We need to make sure Python, ZeroMQ Python and Protocol Buffer are already installed. Writing program in Python can be very short so it’s good to test in server first.
Here we will compile message.proto
file and generate message_pb2.py
file. We need to import this ‘message_pb2.py’ file in the program
<...omitted...>
if (os.path.exists("message_pb2.py") == False):
subprocess.call("protoc message.proto --python_out='.'", shell=True)
<...omitted...>
Then we will setup ZeroMQ
and bind to the Raspberry Pi localhost IP address.
<...omitted...>
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:5556")
<...omitted...>
Now we will parse String from the message that sent from client.
<...omitted...>
message = socket.recv()
addressBook = message_pb2.AddressBook()
addressBook.ParseFromString(message)
<...omitted...>
The complete program of this file can be read from here.
3.3 Ubuntu
In Ubuntu system, we will be using Qt, ZeroMQ and Protocol Buffer so make sure they are already installed. Since we will be using C++, there are more setup required to make it works.
In order to compile *.proto
file, we use *.pri
file in Qt to compile and generate message.pb.h
. Honestly I don’t write the ‘.pri’ file so I can’t explain it. Basically, it generates ‘.ph.h’ and ‘.ph.cc’ files at its own directory. You can read more detail from here.
At Client.cpp, we will setup ZeroMQ
and register the ZeroMQ slot.
<...omitted...>
socket = mContext->createSocket(ZMQSocket::TYP_REQ, this);
QObject::connect(socket, SIGNAL(messageReceived(QList<QByteArray>)), SLOT(onReceivedFromZqmlToConsumeData(QList<QByteArray>)));
mContext->start();
<...omitted...>
Still in Client.cpp, we will setup network
and connect to Raspberry Pi Server.
<...omitted...>
QString raspberryPiAddress = "192.168.1.104";
_initilizeConnection();
const int portNumber = 5556;
QString stringPortNumber = QString::number(portNumber);
QString ipAddressString = "tcp://" + raspberryPiAddress.toLocal8Bit() + ":" +stringPortNumber.toLocal8Bit();
QByteArray qByteArray = ipAddressString.toLatin1();
const char *charIpAddress = qByteArray.data();
socket->connectTo(charIpAddress);
<...omitted...>
While still Client.cpp, we add two Person to Address Book, serialize
the data and send to Raspberry Pi server.
<...omitted...>
message::AddressBook addressBook;
message::Person *john = addressBook.add_person();
john->set_name("John ");
john->set_email("john@abc.com");
message::Person *drake = addressBook.add_person();
drake->set_name("Drake");
drake->set_email("drake@abc.com");
qDebug() << "Number of Person in Address Book: " << addressBook.person_size();
std::string msg_str;
addressBook.SerializeToString(&msg_str);
_sendStringToServer(msg_str.c_str());
<...omitted...>
The complete program of this file can be read from here.
4. Testing Result
We should first run the server program at Raspberry Pi. After that, we will run Qt program. Both of program will generate necessary compiled files from *.proto
file.
The output result at Qt client
will be like this.
Number of Person in Address Book: 2
Hello John
Your email will be john@abc.com
Hello Drake
Your email will be drake@abc.com
Received Msg from Server is "Hello Client"
And the server
side will be displayed like the following.
Number of Person in Address Book: 2
Hello John
Your email will be john@abc.com
Hello Drake
Your email will be drake@abc.com
Received Msg from Server is "Hello Client"