Ronald Ku
Ronald Ku

Reputation: 329

zmq crash in the second loop when recv message of an encoded image through tcp

In the following example with the usage of zmq and opencv encode and decode, the server crash in the recv() function after it shows the first image received. I would like to know if anyone know the reason why the code crashes.

The crash message is "C++ exception: zmq::error_t at memory location."

server

#include <zmq.hpp>
#include <string.h>
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include "fstream"
#include "iostream"
int main()
{
    //  Prepare our context and socket
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:6666");
    while (true)
    {
        //  receive message
        std::string msgStr;
        {
            zmq::message_t message;
            socket.recv(&message);
            msgStr = std::string((char*)message.data(), message.size());
        }
        //  unserialize to cv::mat
        cv::Mat loaded_data;
        {
            std::vector<uchar> data(msgStr.begin(), msgStr.end());
            loaded_data = cv::imdecode(data, CV_LOAD_IMAGE_GRAYSCALE);
        }
        //  show cv::mat
        {
            std::cout << "waiting for your key press on the image." << "\n";
            cv::imshow("load", loaded_data);
            cv::waitKey(0);
        }
    }
    socket.close();
    return 0;
}

client

#include <stdio.h>
#include <opencv2/opencv.hpp>
#include "fstream"
#include "iostream"
int main()
{
    zmq::context_t context(1);
    zmq::socket_t sock(context, ZMQ_REQ);
    sock.connect("tcp://localhost:6666");
    std::string data;
    {
        cv::Mat Imgdata = cv::imread("wall.jpg", CV_LOAD_IMAGE_GRAYSCALE);
        std::vector<uchar> data_encode;
        cv::imencode(".jpg", Imgdata, data_encode);
        data = std::string(data_encode.begin(), data_encode.end());
    }
    // send
    {
        zmq::message_t message(data.size());
        memcpy(message.data(), data.c_str(), data.size());
        sock.send(message);
    }
    sock.close();
    system("pause");
    return 0;
}

Upvotes: 3

Views: 1344

Answers (1)

Clonk
Clonk

Reputation: 2070

Do not disregard the return of the recv function. Doing if(socket.recv(...)) { // Process image } will avoid executing code in case of an error during reception.

You are using REQ / REP Socket. This is a synchrone protocol. REQ can initially send a message and are in blocked stated as long as they don't have a reply to the request. REP can initially receive a message and are in blocked stated as long as they haven't answered the request.

Either reply to the REQ socket after receiving the first image or use another pattern : ZMQ_PAIR, PUSH / PULL, ROUTER / DEALER could all work in your case. Read the documentation to learn about the different pattern.

Also, you don't have to convert your image in a string. You can directly send std::vector<uint8_t>using zmq : you can access the underlying pointer using std::vector::data() and memcpy(message.data(), vector.data(), vector.size()).

Upvotes: 4

Related Questions