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;
-
}