C++之ZeroMQ的使用

zeromq官网的使用教程很详细,这里主要介绍两种常使用的模式。

  1. Request/Reply (请求应答模式)

在这里插入图片描述
这种模式和网络API请求一样,先向一地址的发送请求,然后等待服务器返回对应的数据或者状态,服务器在后端一直监听发过来的请求,然后返回对应的数据即可。
这里代码都是cppzmq的封装的。

void sendMsg()
{
	int port=5555;
    std::cout << "send message ..." << std::endl;
    zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_REQ);
    socket.connect ("tcp://192.168.0.110:" + std::to_string(port));  // 这里选择connect 具体的地址和端口号
    std::string str = "1001";  // 发送的内容
    zmq::message_t msg(str.size());
    memcpy(msg.data(), str.data(), str.size());
    bool ok = socket.send(msg);
    if(ok){
        std::cout << "send success" << std::endl;
    }else {
        std::cout << "send failed" << std::endl;
    }
    std::cout << "send message finished" << std::endl;

    //  等待服务器返回的响应
    zmq::message_t reply;
    socket.recv (&reply);
    std::cout << reply.size() << std::endl;
    char* buffer=new char[reply.size()];
    memcpy(buffer, reply.data(), reply.size());
	std::cout << std::string(buffer)  << std::endl;
    delete[] buffer;
}

服务器端代码:

void receiveMsg()
{
    zmq::context_t ctx;
    zmq::socket_t socket (ctx, ZMQ_REP);
    socket.bind ("tcp://*:5555");  // 监听所有的IP地址
    while (true) {
        zmq::message_t request;
        bool ok = socket.recv(&request);
        if(ok){
            char* buffer = new char[request.size()];
            memcpy(buffer , request.data (), request.size());
            std::cout << "receive:" << std::string(buffer)<< std::endl;
            delete[] buffer
            zmq::message_t reply (2);
            memcpy (reply.data (), "ok", 2);
            socket.send (reply);
        }
    }
}

  1. publish/subscribe (发布订阅模式)

在这里插入图片描述
这种模式类似于广播,当发布者发布信息后,只有订阅者订阅了才能收到信息。有时候应用中会用到视频流信息,这样的话,可以采用该模式,发布者不断的发布图片,而订阅者去订阅地址即可。

上代码,代码中用到了OpenCV图像库,可以对图像进行编码和解码

void  pubImage()
{
     zmq::context_t context (1);
     zmq::socket_t socket (context, ZMQ_PUB);
     socket.bind("tcp://192.168.0.100:5555");   // 这里是绑定地址
     cv::VideoCapture cap(0);  // 打开摄像头
     cv::Mat frame;
     std::vector<uchar> data_encode;
    while (true) {
      data_encode.clear();
      cap.read(frame);
      cv::imencode(".jpg", frame, data_encode);  // 编码图片
      std::cout<< "imencode" << std::endl;
      zmq::message_t msg(data_encode.size());
      memcpy(msg.data(), data_encode.data(), data_encode.size());
      bool ok = socket.send(msg); // 发送数据
      if(!ok){
          std::cout<< "send failed" << std::endl;
      }else{
          std::cout<< "send ok" << std::endl;
      }
   }
}

订阅端

void subscribe()
{
   	zmq::context_t ctx(1);
    zmq::socket_t socket (ctx, ZMQ_SUB);
    socket.connect ("tcp://192.168.0.100:5555");
    socket.setsockopt(ZMQ_SUBSCRIBE, nullptr, 0); //这里是需要设置channel,也就是发送的数据的开头,这里设置为nullptr,长度为0 意思是对接收的消息不过滤,如果设置比如socket.setsockopt(ZMQ_SUBSCRIBE, "AB", 2) 只接收以AB开头的消息,2为AB的长度。
    std::cout << "subscribe" <<  std::endl;
    char key;
    cv::Mat img_decode;
    while (true) {
        std::cout <<"subscribe ..." << std::endl;
        zmq::message_t request;
        auto ok = socket.recv(&request);
        std::vector<uchar> data_reply;
        if(ok){
            data_reply.resize(request.size());
            memcpy (data_reply.data(), request.data (), request.size());

            img_decode = cv::imdecode(data_reply, cv::IMREAD_COLOR);
            cv::imshow("img_decode", img_decode);
            if((char)cv::waitKey(1) == 'q'){
                cv::imwrite("D://1.jpg", img_decode);
            };
        }
    }
}

总结: 在使用的时候一定要搞清楚,哪个是bind,哪个是connect 这个很容易搞混,另外,就是订阅的时候对消息的过滤条件要写对。

发布了24 篇原创文章 · 获赞 4 · 访问量 8291

猜你喜欢

转载自blog.csdn.net/zhaitianyong/article/details/104716004
今日推荐