zeromq的使用

1. 下载zeromq

 C: git clone http://github.com/zeromq/libzmq;

2. 编译

编译zmqlib:启动开始菜单 vs2017下的x64 Native Tools Command Prompt for VS 2017。

mkdir -p src\libzmq\build;

cd src\libzmq\build;

cmake ..

vs2017打开ZeroMQ.sln。编译。

3.使用:

A.publisher-subscriber模式

server:

#include <zmq.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#if (!defined (WIN32))
#   include <sys/time.h>
#endif
#if (defined (WIN32))
#   include <windows.h>
#endif
int main (void)
{
    //  Prepare our context and publisher
    void *context = zmq_ctx_new ();
    void *publisher = zmq_socket (context, ZMQ_PUB);
    int rc = zmq_bind (publisher, "tcp://*:5556");
    assert (rc == 0);
    //  Initialize random number generator
    srand((unsigned) time (NULL));
    while (1) {
        //  Get values that will fool the boss
        int zipcode, temperature, relhumidity;
        zipcode     = rand()%(100000);
        temperature = rand()%(215) - 80;
        relhumidity = rand()%(50) + 10;
        //  Send message to all subscribers
        char update [20];
        sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity);
        zmq_send (publisher, update, strlen (update), 0);
    }
    zmq_close (publisher);
    zmq_ctx_destroy (context);
    return 0;
}


client:

#include <zmq.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#if (!defined (WIN32))
#   include <sys/time.h>
#endif
#if (defined (WIN32))
#   include <windows.h>
#endif
int main (int argc, char *argv [])
{
    //  Socket to talk to server
    printf ("Collecting updates from weather server...\n");
    void *context = zmq_ctx_new ();
    void *subscriber = zmq_socket (context, ZMQ_SUB);
    int rc = zmq_connect (subscriber, "tcp://localhost:5556");
    assert (rc == 0);
    //  Subscribe to zipcode, default is NYC, 10001
    const char *filter = (argc > 1)? argv [1]: "10001 ";
    rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,
                         filter, strlen (filter));
    assert (rc == 0);
    //  Process 100 updates
    int update_nbr;
    long total_temp = 0;
    for (update_nbr = 0; update_nbr < 100; update_nbr++) {
        char buffer [256];
        int size = zmq_recv (subscriber, buffer, 255, 0);
        if (size == -1)
            continue;
        buffer[size] = '\0';
        int zipcode, temperature, relhumidity;
        sscanf (buffer, "%d %d %d",
            &zipcode, &temperature, &relhumidity);
        total_temp += temperature;
    }
    printf ("Average temperature for zipcode '%s' was %dF\n",
        filter, (int) (total_temp / update_nbr));
    zmq_close (subscriber);
    zmq_ctx_destroy (context);
    return 0;
}

B.request-response模式:

server:

#include <zmq.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>
#if (!defined (WIN32))
#   include <sys/time.h>
#endif
#if (defined (WIN32))
#   include <windows.h>
#endif
int main (void)
{
    //  Socket to talk to clients
    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    int rc = zmq_bind (responder, "tcp://*:5555");
    assert (rc == 0);
    while (1) {
        char buffer [10];
        zmq_recv (responder, buffer, 10, 0);
        printf ("Received Hello\n");
        Sleep (1);          //  Do some 'work'
        zmq_send (responder, "World", 5, 0);
    }
    return 0;
}

client:

#include <zmq.h>
#include <string.h>
#include <stdio.h>
int main (void)
{
    printf ("Connecting to hello world server...\n");
    void *context = zmq_ctx_new ();
    void *requester = zmq_socket (context, ZMQ_REQ);
    zmq_connect (requester, "tcp://localhost:5555");
    int request_nbr;
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {
        char buffer [10];
        printf ("Sending Hello %d...\n", request_nbr);
        zmq_send (requester, "Hello", 5, 0);
        zmq_recv (requester, buffer, 10, 0);
        printf ("Received World %d\n", request_nbr);
    }
    zmq_close (requester);
    zmq_ctx_destroy (context);
    return 0;
}


C. ROUTER -DEALER模式
server端:

qyhzmqserverworker.h:

#ifndef QYHZMQSERVERWORKER_H
#define QYHZMQSERVERWORKER_H

#include <zmq.hpp>

class QyhZmqServerWorker
{
public:
    QyhZmqServerWorker(void *ctx);
    void work();
private:
    zmq::context_t *ctx_;
    zmq::socket_t worker_;
};

#endif // QYHZMQSERVERWORKER_H


qyhzmqserverworker.cpp:

#include "qyhzmqserverworker.h"

QyhZmqServerWorker::QyhZmqServerWorker(void *ctx):
    ctx_((zmq::context_t *)ctx),
    worker_(*ctx_, ZMQ_REP)
{

}

void QyhZmqServerWorker::work()
{
    worker_.connect("inproc://workers");

    try {
        while (true) {
            zmq::message_t msg;
            zmq::message_t copied_msg;
            worker_.recv(&msg);
            //处理结尾没有\0的问题
            printf("recv:%s\n",std::string((char*)msg.data(),msg.size()).c_str());
            copied_msg.copy(&msg);
            worker_.send(copied_msg);
        }
    }
    catch (std::exception &e) {}
}


qyhzmqserver.h:

#ifndef QYHZMQSERVER_H
#define QYHZMQSERVER_H

#include <vector>
#include <thread>
#include <memory>
#include <functional>

#include <zmq.hpp>


class QyhZmqServer
{
public:
    QyhZmqServer();

    //线程数量
    enum{ MAX_THREAD = 10 };

    //线程中初始化的入口
    void run();
private:
    zmq::context_t ctx_;
    zmq::socket_t frontend_;
    zmq::socket_t backend_;
};

#endif // QYHZMQSERVER_H

qyhzmqserver.cpp:

#include "qyhzmqserver.h"
#include "qyhzmqserverworker.h"

QyhZmqServer::QyhZmqServer():
    ctx_(1),
    frontend_(ctx_, ZMQ_ROUTER),
    backend_(ctx_, ZMQ_DEALER)
{

}

void QyhZmqServer::run()
{
    frontend_.bind("tcp://*:5555");
    backend_.bind("inproc://workers");

    std::vector<QyhZmqServerWorker *> worker;
    std::vector<std::thread *> worker_thread;

    for (int i = 0; i < MAX_THREAD; ++i)
    {
        //一个新的工人
        worker.push_back(new QyhZmqServerWorker((void *)&ctx_));

        //启动一个线程,执行这个工人的 work函数
        worker_thread.push_back(new std::thread(std::bind(&QyhZmqServerWorker::work, worker[i])));
        worker_thread[i]->detach();
    }

    //执行代理操作
    try {
        zmq::proxy(frontend_, backend_, nullptr);
    }
    catch (std::exception &e) {}

    for (int i = 0; i < MAX_THREAD; ++i) {
        delete worker[i];
        delete worker_thread[i];
    }
}

main.cpp:

#include "qyhzmqserver.h"

int main(int argc, char *argv[])
{
    QyhZmqServer server;
    std::thread t(std::bind(&QyhZmqServer::run, &server));
    t.detach();
    getchar();
    return 0;
}

CLIENT端:
main.cpp:

#include <vector>
#include <thread>
#include <memory>
#include <functional>

#include <zmq.hpp>
#include "zhelpers.hpp"

class client_task {
public:
    client_task()
        : ctx_(1),
          client_socket_(ctx_, ZMQ_REQ)
    {}

    void start() {

        client_socket_.connect("tcp://localhost:5555");

        int timeout = 1000;
        zmq_setsockopt (client_socket_, ZMQ_RCVTIMEO, &timeout, sizeof(timeout));
        zmq_setsockopt (client_socket_, ZMQ_SNDTIMEO, &timeout, sizeof(timeout));

        int request_nbr = 0;

        //这里出现异常,就直接退出了线程!
        try {
            while (true) {
                std::stringstream ss;
                ss<<"request :"<< ++request_nbr;
                std::string data = ss.str();

                zmq::message_t s(data.c_str(),data.length());
                client_socket_.send(s);
                zmq::message_t m;
                client_socket_.recv(&m);
                printf("recv:%s\n",std::string((char *)m.data(),m.size()).c_str());
                Sleep(1000);
            }
        }
        catch (std::exception &e) {}

    }

private:
    zmq::context_t ctx_;
    zmq::socket_t client_socket_;
};

int main (void)
{
    client_task ct1;
    client_task ct2;
    client_task ct3;

    std::thread(std::bind(&client_task::start, &ct1)).detach();
    std::thread(std::bind(&client_task::start, &ct2)).detach();
    std::thread(std::bind(&client_task::start, &ct3)).detach();

    getchar();
    return 0;
}


 
对subscriber的简单封装,以供大家参考。解决了多线程调用的问题,并且可以自由 开始停止。实现了优雅的启动停止。
qyhzmqsubscriber.h

#ifndef QYHZMQSUBSCRIBER_H
#define QYHZMQSUBSCRIBER_H

#include <functional>
#include <thread>
#include <zmq.hpp>

class QyhZmqSubscriber
{
public:
    //回调绑定
    typedef std::function<void (std::string)> QyhZmqSubscriberCallback;

    QyhZmqSubscriber(const std::string _url, QyhZmqSubscriberCallback _subcallback);
    ~QyhZmqSubscriber();

    //开始订阅
    void start();

    //停止订阅
    void stop();

private:
    void messageloop();
    static void messagethread(void *arg);
private:
    volatile bool isStop;
    std::thread msgThread;
    zmq::context_t* context;
    zmq::socket_t* subscriber;
    std::string url;
    QyhZmqSubscriberCallback subcallback;
};

#endif // QYHZMQSUBSCRIBER_H


qyhzmqsubscriber.cpp

#include "qyhzmqsubscriber.h"
#include "global.h"

QyhZmqSubscriber::QyhZmqSubscriber(const std::string _url, QyhZmqSubscriberCallback _subcallback):
    url(_url),
    subcallback(_subcallback),
    isStop(true),
    context(NULL)
{
}

QyhZmqSubscriber::~QyhZmqSubscriber()
{
    stop();
}

//开始订阅
void QyhZmqSubscriber::start()
{
    if(!isStop)return ;//运行中
    isStop=false;
    msgThread = std::thread(&QyhZmqSubscriber::messagethread, this);
}

//停止订阅
void QyhZmqSubscriber::stop()
{
    if(isStop)return ;//已停止
    isStop = true;
    delete context;
    if(msgThread.joinable())
        msgThread.join();
}

void QyhZmqSubscriber::messagethread(void *arg)
{
    ((QyhZmqSubscriber *)arg)->messageloop();
}

void QyhZmqSubscriber::messageloop()
{
    //非停止订阅的状态
    context = new zmq::context_t(1);
    subscriber = new zmq::socket_t(*context,ZMQ_SUB);
    subscriber->connect(url);
    subscriber->setsockopt(ZMQ_SUBSCRIBE, "", 0);

    while(!isStop)
    {
        zmq::message_t message;
        try{
            subscriber->recv(&message);
        }catch(std::exception& e){
            //被终止时,会抛出异常
        }
        if(isStop)break;

        std::string str = std::string(static_cast<char*>(message.data()), message.size());
        if(subcallback==nullptr){
            continue;
        }else{
            subcallback(str);
        }
    }
    delete subscriber;
}


main.cpp

#include <iostream>
#include "qyhzmqsubscriber.h"

class LogSubscriber
{
public:
    LogSubscriber():sub(NULL)
    {

    }
    ~LogSubscriber()
    {
        if(sub){
            delete sub;
            sub = NULL;
        }
    }
    void init()
    {
        if(sub)
        {
            delete sub;
            sub = NULL;
        }

        //配置参数
        std::string url = "tcp://localhost:5555";
        QyhZmqSubscriber::QyhZmqSubscriberCallback subcallback = std::bind(&LogSubscriber::onSub, this, std::placeholders::_1);
        sub = new QyhZmqSubscriber(url,subcallback);
    }
    void startSub()
    {
        sub->start();
    }
    void stopSub()
    {
        sub->stop();
    }
private:
    void onSub(std::string msg)
    {
        //your msg process
        std::cout<<msg<<std::endl;
    }
private:
    QyhZmqSubscriber *sub;
};


int main(int argc, char const *argv[])
{
    LogSubscriber logsub;
    logsub.init();
    bool quit = false;
    while(!quit){
        char c;
        std::cin>>c;
        switch(c){
        case 's':logsub.startSub();break;
        case 't':logsub.stopSub();break;
        case 'q':quit=true;break;
        }
    }
    return 0;
}


运行结果截图

 
---------------------  
作者:jsqinyinghao  
来源:CSDN  
原文:https://blog.csdn.net/qinyinghao/article/details/79000977?utm_source=copy  
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/dickshell/article/details/83026933