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:
- 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:
- 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:
- 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:
- 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:
- class QyhZmqServerWorker
- {
- public:
- QyhZmqServerWorker(void *ctx);
- void work();
- private:
- zmq::context_t *ctx_;
- zmq::socket_t worker_;
- };
- 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:
- class QyhZmqServer
- {
- public:
- QyhZmqServer();
- //线程数量
- enum{ MAX_THREAD = 10 };
- //线程中初始化的入口
- void run();
- private:
- zmq::context_t ctx_;
- zmq::socket_t frontend_;
- zmq::socket_t backend_;
- };
qyhzmqserver.cpp:
- 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:
- int main(int argc, char *argv[])
- {
- QyhZmqServer server;
- std::thread t(std::bind(&QyhZmqServer::run, &server));
- t.detach();
- getchar();
- return 0;
- }
main.cpp:
- 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
- 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;
- };
qyhzmqsubscriber.cpp
- 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;
- }
- 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;
- }