Reputation: 77
I have a C++ server and client code with zmq ( ZeroMQ ) lib. I would like to send integer values to the client.
I have read through the manual for zmq, but I have a problem sending anything else than a char array from the server to client.
Can anyone help me with the code? Thanks in advance.
Upvotes: 1
Views: 3365
Reputation: 3033
Its always better to encode your data packet before sending them over zmq. Avoiding this can be problematic with large datasets or arrays too. As a general example, let me share how to send encoded packets using the example of a REQ/REP
socket between a Python client and C++ server; the client requests the server by sending the image in base64 encoded form. To which, the server replies by returning a resultant array, again encoded as a C string.
import time
import zmq
import base64
def producer():
context = zmq.Context()
zmq_socket = context.socket(zmq.REQ)
zmq_socket.connect("tcp://127.0.0.1:5556")
# Start your result manager and workers before you start your producers
# Read image to send
f = open("/home/virus/Desktop/optimisation/test.ppm",'rb')
bytes = bytearray(f.read());
# encode
strng = base64.b64encode(bytes)
# send/Request
start = time.time();
zmq_socket.send(strng)
# Get reply
result = zmq_socket.recv();
# Convert bytes to string
decodedResult = result.decode("utf-8")
# parse the string back to an array
parsedArray = list(map(int, decodedResult.split(" ")))
print("\ntime: ",time.time()-start)
# Close socket
f.close()
zmq_socket.close()
producer()
#include <zmq.h>
#include <assert.h>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fstream> // for writing files
#include <iostream>
typedef unsigned char uchar;
using namespace std;
vector<pair<int,int>> arr;
static string base64_decode(const string &in) {
// Ref: https://stackoverflow.com/a/34571089/9625777
string out;
vector<int> T(256,-1);
for (int i=0; i<64; i++)
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
int val=0, valb=-8;
for (uchar c : in) {
if (T[c] == -1) break;
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val>>valb)&0xFF));
valb -= 8;
}
}
return out;
}
int main ()
{
while(1) // Stay ON eternally
{
// Create socket
void *context = zmq_ctx_new ();
void *responder = zmq_socket (context, ZMQ_REP);
int rc = zmq_bind(responder, "tcp://*:5556");
assert (rc == 0);
//{
// The zmq_connect() function returns zero if successful.
// Otherwise it returns -1
//}
cout << "\nGot a connection";
// Receive data/Request
char buffer [4194328]; // big enough to accomodate selected image
auto nbytes = zmq_recv (responder, buffer, 4194328, 0);assert (nbytes != -1);
cout << "Got a request";
// Do something with the received image
// decode data
auto decodedData = base64_decode(buffer);
// write results to a file
ofstream myFile("res.ppm");
myFile << decodedData;
myFile.close();
// Generate dummy reply/response
int n=10,i,j;
int arr[n+4] = {11, 21, 31, 441};
for(i=0,j=4; i<n; i++,j++)
{
arr[j] = (i+1)*11;
}
// Encode to a C++ string
std::string str;
for (int i: arr) {
str += std::to_string(i);
str += " "; //Add whitespace as delimiter
}
// remove last redundant whitespace
str.pop_back();
// Create zmq message envelope reply
zmq_msg_t msg;
rc = zmq_msg_init_size (&msg, sizeof(arr)); cout << "\nsizeof(arr): "<<sizeof(arr);
assert (rc == 0);
// Convert c++ type string to C type. ZMQ doesn't allow sending C++ type strings
char * cstr = new char [str.length()+1];
strcpy (cstr, str.c_str());
// cstr now contains a c-string copy of str
// Send Result/Response
cout << "\nsending C-string: " << cstr << "\tstrlen(cstr): " << strlen(cstr);
rc = zmq_send(responder, cstr, strlen(cstr), 0); cout << "\nsizeof(cstr): "<<sizeof(cstr);
assert(rc != -1);
/*Note that we use `strlen(cstr)` and NOT `sizeof(cstr)` because `zmq_send` takes length*/
// Close socket
zmq_close (responder);
zmq_ctx_destroy (context);
}
return 0;
}
Note that the zmq lib was installed using sudo apt-get install libzmq3-dev
.
The Cpp script must be compile using valid linker flags.
$ gcc -Wall -g server.cpp -lzmq -lstdc++ -o server
Upvotes: 1
Reputation: 1042
You just need a message format.
Size efficient would be a struct:
Send side
struct Message
{
uint32_t one;
uint64_t two;
};
Message msg;
msg.one = 1;
msg.two = 20;
send(&msg, sizeof(Message));
Or if you want something more flexible you could send json etc
Receive side:
assuming you use cppzmq headers
Message* msg;
zmq::message_t zmsg;
sock->recv(&zmsg);
msg = (Message*)zmsg.data();
int one - msg->one;
Upvotes: 2