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:

  1. #include <zmq.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <time.h>
  7. #if (!defined (WIN32))
  8. # include <sys/time.h>
  9. #endif
  10. #if (defined (WIN32))
  11. # include <windows.h>
  12. #endif
  13. int main (void)
  14. {
  15. // Prepare our context and publisher
  16. void *context = zmq_ctx_new ();
  17. void *publisher = zmq_socket (context, ZMQ_PUB);
  18. int rc = zmq_bind (publisher, "tcp://*:5556");
  19. assert (rc == 0);
  20. // Initialize random number generator
  21. srand(( unsigned) time ( NULL));
  22. while ( 1) {
  23. // Get values that will fool the boss
  24. int zipcode, temperature, relhumidity;
  25. zipcode = rand()%( 100000);
  26. temperature = rand()%( 215) - 80;
  27. relhumidity = rand()%( 50) + 10;
  28. // Send message to all subscribers
  29. char update [ 20];
  30. sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity);
  31. zmq_send (publisher, update, strlen (update), 0);
  32. }
  33. zmq_close (publisher);
  34. zmq_ctx_destroy (context);
  35. return 0;
  36. }



client:

  1. #include <zmq.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <time.h>
  7. #if (!defined (WIN32))
  8. # include <sys/time.h>
  9. #endif
  10. #if (defined (WIN32))
  11. # include <windows.h>
  12. #endif
  13. int main (int argc, char *argv [])
  14. {
  15. // Socket to talk to server
  16. printf ( "Collecting updates from weather server...\n");
  17. void *context = zmq_ctx_new ();
  18. void *subscriber = zmq_socket (context, ZMQ_SUB);
  19. int rc = zmq_connect (subscriber, "tcp://localhost:5556");
  20. assert (rc == 0);
  21. // Subscribe to zipcode, default is NYC, 10001
  22. const char *filter = (argc > 1)? argv [ 1]: "10001 ";
  23. rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,
  24. filter, strlen (filter));
  25. assert (rc == 0);
  26. // Process 100 updates
  27. int update_nbr;
  28. long total_temp = 0;
  29. for (update_nbr = 0; update_nbr < 100; update_nbr++) {
  30. char buffer [ 256];
  31. int size = zmq_recv (subscriber, buffer, 255, 0);
  32. if (size == -1)
  33. continue;
  34. buffer[size] = '\0';
  35. int zipcode, temperature, relhumidity;
  36. sscanf (buffer, "%d %d %d",
  37. &zipcode, &temperature, &relhumidity);
  38. total_temp += temperature;
  39. }
  40. printf ( "Average temperature for zipcode '%s' was %dF\n",
  41. filter, ( int) (total_temp / update_nbr));
  42. zmq_close (subscriber);
  43. zmq_ctx_destroy (context);
  44. return 0;
  45. }

B.request-response模式:

server:

  1. #include <zmq.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #if (!defined (WIN32))
  6. # include <sys/time.h>
  7. #endif
  8. #if (defined (WIN32))
  9. # include <windows.h>
  10. #endif
  11. int main (void)
  12. {
  13. // Socket to talk to clients
  14. void *context = zmq_ctx_new ();
  15. void *responder = zmq_socket (context, ZMQ_REP);
  16. int rc = zmq_bind (responder, "tcp://*:5555");
  17. assert (rc == 0);
  18. while ( 1) {
  19. char buffer [ 10];
  20. zmq_recv (responder, buffer, 10, 0);
  21. printf ( "Received Hello\n");
  22. Sleep ( 1); // Do some 'work'
  23. zmq_send (responder, "World", 5, 0);
  24. }
  25. return 0;
  26. }


client:

  1. #include <zmq.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. int main (void)
  5. {
  6. printf ( "Connecting to hello world server...\n");
  7. void *context = zmq_ctx_new ();
  8. void *requester = zmq_socket (context, ZMQ_REQ);
  9. zmq_connect (requester, "tcp://localhost:5555");
  10. int request_nbr;
  11. for (request_nbr = 0; request_nbr != 10; request_nbr++) {
  12. char buffer [ 10];
  13. printf ( "Sending Hello %d...\n", request_nbr);
  14. zmq_send (requester, "Hello", 5, 0);
  15. zmq_recv (requester, buffer, 10, 0);
  16. printf ( "Received World %d\n", request_nbr);
  17. }
  18. zmq_close (requester);
  19. zmq_ctx_destroy (context);
  20. return 0;
  21. }

C. ROUTER -DEALER模式
server端:

qyhzmqserverworker.h:
  1. #ifndef QYHZMQSERVERWORKER_H
  2. #define QYHZMQSERVERWORKER_H
  3. #include <zmq.hpp>
  4. class QyhZmqServerWorker
  5. {
  6. public:
  7. QyhZmqServerWorker( void *ctx);
  8. void work();
  9. private:
  10. zmq:: context_t *ctx_;
  11. zmq:: socket_t worker_;
  12. };
  13. #endif // QYHZMQSERVERWORKER_H

qyhzmqserverworker.cpp:
  1. #include "qyhzmqserverworker.h"
  2. QyhZmqServerWorker::QyhZmqServerWorker( void *ctx):
  3. ctx_((zmq:: context_t *)ctx),
  4. worker_(*ctx_, ZMQ_REP)
  5. {
  6. }
  7. void QyhZmqServerWorker::work()
  8. {
  9. worker_.connect( "inproc://workers");
  10. try {
  11. while ( true) {
  12. zmq:: message_t msg;
  13. zmq:: message_t copied_msg;
  14. worker_.recv(&msg);
  15. //处理结尾没有\0的问题
  16. printf( "recv:%s\n", std:: string(( char*)msg.data(),msg.size()).c_str());
  17. copied_msg.copy(&msg);
  18. worker_.send(copied_msg);
  19. }
  20. }
  21. catch ( std::exception &e) {}
  22. }

qyhzmqserver.h:
  1. #ifndef QYHZMQSERVER_H
  2. #define QYHZMQSERVER_H
  3. #include <vector>
  4. #include <thread>
  5. #include <memory>
  6. #include <functional>
  7. #include <zmq.hpp>
  8. class QyhZmqServer
  9. {
  10. public:
  11. QyhZmqServer();
  12. //线程数量
  13. enum{ MAX_THREAD = 10 };
  14. //线程中初始化的入口
  15. void run();
  16. private:
  17. zmq:: context_t ctx_;
  18. zmq:: socket_t frontend_;
  19. zmq:: socket_t backend_;
  20. };
  21. #endif // QYHZMQSERVER_H


qyhzmqserver.cpp:
  1. #include "qyhzmqserver.h"
  2. #include "qyhzmqserverworker.h"
  3. QyhZmqServer::QyhZmqServer():
  4. ctx_( 1),
  5. frontend_(ctx_, ZMQ_ROUTER),
  6. backend_(ctx_, ZMQ_DEALER)
  7. {
  8. }
  9. void QyhZmqServer::run()
  10. {
  11. frontend_.bind( "tcp://*:5555");
  12. backend_.bind( "inproc://workers");
  13. std:: vector<QyhZmqServerWorker *> worker;
  14. std:: vector< std::thread *> worker_thread;
  15. for ( int i = 0; i < MAX_THREAD; ++i)
  16. {
  17. //一个新的工人
  18. worker.push_back( new QyhZmqServerWorker(( void *)&ctx_));
  19. //启动一个线程,执行这个工人的 work函数
  20. worker_thread.push_back( new std::thread( std::bind(&QyhZmqServerWorker::work, worker[i])));
  21. worker_thread[i]->detach();
  22. }
  23. //执行代理操作
  24. try {
  25. zmq::proxy(frontend_, backend_, nullptr);
  26. }
  27. catch ( std::exception &e) {}
  28. for ( int i = 0; i < MAX_THREAD; ++i) {
  29. delete worker[i];
  30. delete worker_thread[i];
  31. }
  32. }


main.cpp:
  1. #include "qyhzmqserver.h"
  2. int main(int argc, char *argv[])
  3. {
  4. QyhZmqServer server;
  5. std:: thread t(std::bind(&QyhZmqServer::run, &server));
  6. t.detach();
  7. getchar();
  8. return 0;
  9. }

CLIENT端:
main.cpp:
  1. #include <vector>
  2. #include <thread>
  3. #include <memory>
  4. #include <functional>
  5. #include <zmq.hpp>
  6. #include "zhelpers.hpp"
  7. class client_task {
  8. public:
  9. client_task()
  10. : ctx_( 1),
  11. client_socket_(ctx_, ZMQ_REQ)
  12. {}
  13. void start() {
  14. client_socket_.connect( "tcp://localhost:5555");
  15. int timeout = 1000;
  16. zmq_setsockopt (client_socket_, ZMQ_RCVTIMEO, &timeout, sizeof(timeout));
  17. zmq_setsockopt (client_socket_, ZMQ_SNDTIMEO, &timeout, sizeof(timeout));
  18. int request_nbr = 0;
  19. //这里出现异常,就直接退出了线程!
  20. try {
  21. while ( true) {
  22. std:: stringstream ss;
  23. ss<< "request :"<< ++request_nbr;
  24. std:: string data = ss.str();
  25. zmq:: message_t s(data.c_str(),data.length());
  26. client_socket_.send(s);
  27. zmq:: message_t m;
  28. client_socket_.recv(&m);
  29. printf( "recv:%s\n", std:: string(( char *)m.data(),m.size()).c_str());
  30. Sleep( 1000);
  31. }
  32. }
  33. catch ( std::exception &e) {}
  34. }
  35. private:
  36. zmq:: context_t ctx_;
  37. zmq:: socket_t client_socket_;
  38. };
  39. int main (void)
  40. {
  41. client_task ct1;
  42. client_task ct2;
  43. client_task ct3;
  44. std::thread( std::bind(&client_task::start, &ct1)).detach();
  45. std::thread( std::bind(&client_task::start, &ct2)).detach();
  46. std::thread( std::bind(&client_task::start, &ct3)).detach();
  47. getchar();
  48. return 0;
  49. }

 
对subscriber的简单封装,以供大家参考。解决了多线程调用的问题,并且可以自由 开始停止。实现了优雅的启动停止。
qyhzmqsubscriber.h
  1. #ifndef QYHZMQSUBSCRIBER_H
  2. #define QYHZMQSUBSCRIBER_H
  3. #include <functional>
  4. #include <thread>
  5. #include <zmq.hpp>
  6. class QyhZmqSubscriber
  7. {
  8. public:
  9. //回调绑定
  10. typedef std::function< void ( std:: string)> QyhZmqSubscriberCallback;
  11. QyhZmqSubscriber( const std:: string _url, QyhZmqSubscriberCallback _subcallback);
  12. ~QyhZmqSubscriber();
  13. //开始订阅
  14. void start();
  15. //停止订阅
  16. void stop();
  17. private:
  18. void messageloop();
  19. static void messagethread(void *arg);
  20. private:
  21. volatile bool isStop;
  22. std::thread msgThread;
  23. zmq:: context_t* context;
  24. zmq:: socket_t* subscriber;
  25. std:: string url;
  26. QyhZmqSubscriberCallback subcallback;
  27. };
  28. #endif // QYHZMQSUBSCRIBER_H

qyhzmqsubscriber.cpp
  1. #include "qyhzmqsubscriber.h"
  2. #include "global.h"
  3. QyhZmqSubscriber::QyhZmqSubscriber( const std:: string _url, QyhZmqSubscriberCallback _subcallback):
  4. url(_url),
  5. subcallback(_subcallback),
  6. isStop( true),
  7. context( NULL)
  8. {
  9. }
  10. QyhZmqSubscriber::~QyhZmqSubscriber()
  11. {
  12. stop();
  13. }
  14. //开始订阅
  15. void QyhZmqSubscriber::start()
  16. {
  17. if(!isStop) return ; //运行中
  18. isStop= false;
  19. msgThread = std::thread(&QyhZmqSubscriber::messagethread, this);
  20. }
  21. //停止订阅
  22. void QyhZmqSubscriber::stop()
  23. {
  24. if(isStop) return ; //已停止
  25. isStop = true;
  26. delete context;
  27. if(msgThread.joinable())
  28. msgThread.join();
  29. }
  30. void QyhZmqSubscriber::messagethread( void *arg)
  31. {
  32. ((QyhZmqSubscriber *)arg)->messageloop();
  33. }
  34. void QyhZmqSubscriber::messageloop()
  35. {
  36. //非停止订阅的状态
  37. context = new zmq:: context_t( 1);
  38. subscriber = new zmq:: socket_t(*context,ZMQ_SUB);
  39. subscriber->connect(url);
  40. subscriber->setsockopt(ZMQ_SUBSCRIBE, "", 0);
  41. while(!isStop)
  42. {
  43. zmq:: message_t message;
  44. try{
  45. subscriber->recv(&message);
  46. } catch( std::exception& e){
  47. //被终止时,会抛出异常
  48. }
  49. if(isStop) break;
  50. std:: string str = std:: string( static_cast< char*>(message.data()), message.size());
  51. if(subcallback== nullptr){
  52. continue;
  53. } else{
  54. subcallback(str);
  55. }
  56. }
  57. delete subscriber;
  58. }

main.cpp

  1. #include <iostream>
  2. #include "qyhzmqsubscriber.h"
  3. class LogSubscriber
  4. {
  5. public:
  6. LogSubscriber():sub( NULL)
  7. {
  8. }
  9. ~LogSubscriber()
  10. {
  11. if(sub){
  12. delete sub;
  13. sub = NULL;
  14. }
  15. }
  16. void init()
  17. {
  18. if(sub)
  19. {
  20. delete sub;
  21. sub = NULL;
  22. }
  23. //配置参数
  24. std:: string url = "tcp://localhost:5555";
  25. QyhZmqSubscriber::QyhZmqSubscriberCallback subcallback = std::bind(&LogSubscriber::onSub, this, std::placeholders::_1);
  26. sub = new QyhZmqSubscriber(url,subcallback);
  27. }
  28. void startSub()
  29. {
  30. sub->start();
  31. }
  32. void stopSub()
  33. {
  34. sub->stop();
  35. }
  36. private:
  37. void onSub(std::string msg)
  38. {
  39. //your msg process
  40. std:: cout<<msg<< std:: endl;
  41. }
  42. private:
  43. QyhZmqSubscriber *sub;
  44. };
  45. int main(int argc, char const *argv[])
  46. {
  47. LogSubscriber logsub;
  48. logsub.init();
  49. bool quit = false;
  50. while(!quit){
  51. char c;
  52. std:: cin>>c;
  53. switch(c){
  54. case 's':logsub.startSub(); break;
  55. case 't':logsub.stopSub(); break;
  56. case 'q':quit= true; break;
  57. }
  58. }
  59. return 0;
  60. }

运行结果截图


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值