Rakshith
Rakshith

Reputation: 77

How to send integer values between server and client using zeromq(zmq)?

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

Answers (2)

Pe Dro
Pe Dro

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.

python client

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

C++ server

#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

jamesdillonharvey
jamesdillonharvey

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

Related Questions