C++測試redis中的publish/subscribe__C++

來源:互聯網
上載者:User
運用 http://blog.csdn.net/xumaojun/article/details/51558237 中的redis_publisher.h redis_publisher.cpp redis_subscriber.h redis_subscriber.cpp四個檔案,做一個操作類進行測試. 標頭檔 Policy.h
#pragma once#include "redis_publisher.h"#include "redis_subscriber.h"#include <iostream>using namespace std;class Policy{public:    Policy();    ~Policy();    void publish();    static void recieve_message(const char *channel_name,const char *message, int len);    CRedisPublisher publisher;    CRedisSubscriber subscriber;};
代碼檔案 Policy.cpp
#include "Policy.h"Policy::Policy(){    bool ret = publisher.init();    if (!ret) {        printf("Init failed.\n");    }    ret = publisher.connect();    if (!ret) {        printf("connect failed.");    }    //***********************************    CRedisSubscriber::NotifyMessageFn fn =        bind(recieve_message, std::tr1::placeholders::_1,             std::tr1::placeholders::_2, std::tr1::placeholders::_3);    bool ret1 = subscriber.init(fn);    if (!ret1) {        printf("Init failed.\n");    }    ret1 = subscriber.connect();    if (!ret1) {        printf("Connect failed.\n");    }    subscriber.subscribe("test-channel");}Policy::~Policy(){    publisher.disconnect();    publisher.uninit();    subscriber.disconnect();    subscriber.uninit();}void Policy::publish(){    cout<<"Policy::publish()...\n"<<endl;    publisher.publish("test-channel", "Test message");}void Policy::recieve_message(const char *channel_name,    const char *message, int len){    printf("Recieve message:    channel name: %s    message: %s\n",        channel_name, message);}

測試檔案 testPolicy.cpp
#include "Policy.h"int main(int argc, char *argv[]){    Policy m_policy;    int i=0;    while(i<8){        m_policy.publish();        sleep(2);        cout<<"main sleep...\n";        i++;    }    return 0;}

Makefile
EXE=server_main client_main  CC=g++  FLAG=-lhiredis -levent -pthread  OBJ=redis_publisher.o redis_subscriber.o Policy.o testPolicy.o  all:$(EXE)$(EXE):$(OBJ)$(CC) -o testPolicy  redis_publisher.o redis_subscriber.o Policy.o testPolicy.o  $(FLAG)  redis_publisher.o:redis_publisher.hredis_subscriber.o:redis_subscriber.hPolicy.o:Policy.h

這樣編譯之後,可以自發自收. 本例的用途在於可以簡單地在項目中實現異構的資料收發.
附上原作代碼: redis_publisher.h
/*************************************************************************     > File Name: redis_publisher.h     > Author: chenzengba     > Mail: chenzengba@gmail.com      > Created Time: Sat 23 Apr 2016 10:15:09 PM CST     > Description: 封裝hiredis,實現訊息發布給redis功能  ************************************************************************/    #ifndef REDIS_PUBLISHER_H  #define REDIS_PUBLISHER_H    #include <stdlib.h>  #include <hiredis/async.h>  #include <hiredis/adapters/libevent.h>  #include <string>  #include <vector>  #include <unistd.h>  #include <pthread.h>  #include <semaphore.h>  #include <boost/tr1/functional.hpp>    class CRedisPublisher  {  public:          CRedisPublisher();      ~CRedisPublisher();        bool init();      bool uninit();      bool connect();      bool disconnect();            bool publish(const std::string &channel_name,           const std::string &message);    private:       // 下面三個回呼函數供redis服務調用      // 串連回調      static void connect_callback(const redisAsyncContext *redis_context,          int status);            // 中斷連線的回調      static void disconnect_callback(const redisAsyncContext *redis_context,          int status);        // 執行命令回調      static void command_callback(redisAsyncContext *redis_context,          void *reply, void *privdata);        // 事件分發線程函數      static void *event_thread(void *data);      void *event_proc();    private:       // libevent事件對象      event_base *_event_base;      // 事件線程ID      pthread_t _event_thread;      // 事件線程的訊號量      sem_t _event_sem;      // hiredis非同步對象      redisAsyncContext *_redis_context;  };    

redis_publisher.cpp
/*************************************************************************     > File Name: redis_publisher.cpp     > Author: chenzengba     > Mail: chenzengba@gmail.com      > Created Time: Sat 23 Apr 2016 10:15:09 PM CST     > Description:   ************************************************************************/     #include <stddef.h>  #include <assert.h>  #include <string.h>  #include "redis_publisher.h"    CRedisPublisher::CRedisPublisher():_event_base(0), _event_thread(0),  _redis_context(0)  {  }    CRedisPublisher::~CRedisPublisher()  {  }    bool CRedisPublisher::init()  {      // initialize the event      _event_base = event_base_new();    // 建立libevent對象      if (NULL == _event_base)      {          printf(": Create redis event failed.\n");          return false;      }        memset(&_event_sem, 0, sizeof(_event_sem));      int ret = sem_init(&_event_sem, 0, 0);      if (ret != 0)      {          printf(": Init sem failed.\n");          return false;      }        return true;  }    bool CRedisPublisher::uninit()  {      _event_base = NULL;            sem_destroy(&_event_sem);         return true;  }    bool CRedisPublisher::connect()  {      // connect redis      _redis_context = redisAsyncConnect("127.0.0.1", 6379);    // 非同步串連到redis伺服器上,使用預設連接埠      if (NULL == _redis_context)      {          printf(": Connect redis failed.\n");          return false;      }        if (_redis_context->err)      {          printf(": Connect redis error: %d, %s\n",               _redis_context->err, _redis_context->errstr);    // 輸出錯誤資訊          return false;      }        // attach the event      redisLibeventAttach(_redis_context, _event_base);    // 將事件綁定到redis context上,使設定給redis的回調跟事件關聯            // 建立事件處理線程      int ret = pthread_create(&_event_thread, 0, &CRedisPublisher::event_thread, this);      if (ret != 0)      {          printf(": create event thread failed.\n");          disconnect();          return false;      }        // 設定串連回調,當非同步呼叫串連後,伺服器處理串連請求結束後調用,通知調用者串連的狀態      redisAsyncSetConnectCallback(_redis_context,           &CRedisPublisher::connect_callback);        // 設定中斷連線回調,當伺服器中斷連線後,通知調用者串連斷開,調用者可以利用這個函數實現重連      redisAsyncSetDisconnectCallback(_redis_context,          &CRedisPublisher::disconnect_callback);        // 啟動事件線程      sem_post(&_event_sem);      return true;  }    bool CRedisPublisher::disconnect()  {      if (_redis_context)      {          redisAsyncDisconnect(_redis_context);          redisAsyncFree(_redis_context);          _redis_context = NULL;      }        return true;  }    bool CRedisPublisher::publish(const std::string &channel_name,      const std::string &message)  {      int ret = redisAsyncCommand(_redis_context,           &CRedisPublisher::command_callback, this, "PUBLISH %s %s",           channel_name.c_str(), message.c_str());      if (REDIS_ERR == ret)      {          printf("Publish command failed: %d\n", ret);          return false;      }        return true;  }    void CRedisPublisher::connect_callback(const redisAsyncContext *redis_context,      int status)  {      if (status != REDIS_OK)      {          printf(": Error: %s\n", redis_context->errstr);      }      else      {          printf(": Redis connected!\n");      }  }    void CRedisPublisher::disconnect_callback(      const redisAsyncContext *redis_context, int status)  {      if (status != REDIS_OK)      {          // 這裡異常退出,可以嘗試重連          printf(": Error: %s\n", redis_context->errstr);      }  }    // 訊息接收回呼函數  void CRedisPublisher::command_callback(redisAsyncContext *redis_context,      void *reply, void *privdata)  {      printf("command callback.\n");      // 這裡不執行任何操作  }    void *CRedisPublisher::event_thread(void *data)  {      if (NULL == data)      {          printf(": Error!\n");          assert(false);          return NULL;      }        CRedisPublisher *self_this = reinterpret_cast<CRedisPublisher *>(data);      return self_this->event_proc();  }    void *CRedisPublisher::event_proc()  {      sem_wait(&_event_sem);            // 開啟事件分發,event_base_dispatch會阻塞      event_base_dispatch(_event_base);        return NULL;  }

redis_subscriber.h
/*************************************************************************     > File Name: redis_subscriber.h     > Author: chenzengba     > Mail: chenzengba@gmail.com      > Created Time: Sat 23 Apr 2016 10:15:09 PM CST     > Description: 封裝hiredis,實現訊息訂閱redis功能  ************************************************************************/    #ifndef REDIS_SUBSCRIBER_H  #define REDIS_SUBSCRIBER_H    #include <stdlib.h>  #include <hiredis/async.h>  #include <hiredis/adapters/libevent.h>  #include <string>  #include <vector>  #include <unistd.h>  #include <pthread.h>  #include <semaphore.h>  #include <boost/tr1/functional.hpp>    class CRedisSubscriber  {  public:      typedef std::tr1::function<void (const char *, const char *, int)>         NotifyMessageFn;   // 回呼函數物件類型,當接收到訊息後調用回調把訊息發送出去                CRedisSubscriber();      ~CRedisSubscriber();            bool init(const NotifyMessageFn &fn);   // 傳入回調對象      bool uninit();      bool connect();      bool disconnect();            // 可以多次調用,訂閱多個頻道      bool subscribe(const std::string &channel_name);        private:      // 下面三個回呼函數供redis服務調用      // 串連回調      static void connect_callback(const redisAsyncContext *redis_context,          int status);            // 中斷連線的回調      static void disconnect_callback(const redisAsyncContext *redis_context,          int status);        // 執行命令回調      static void command_callback(redisAsyncContext *redis_context,          void *reply, void *privdata);        // 事件分發線程函數      static void *event_thread(void *data);      void *event_proc();        private:      // libevent事件對象      event_base *_event_base;      // 事件線程ID      pthread_t _event_thread;      // 事件線程的訊號量      sem_t _event_sem;      // hiredis非同步對象      redisAsyncContext *_redis_context;            // 通知外層的回呼函數對象      NotifyMessageFn _notify_message_fn;  };    

redis_subscriber.cpp
/*************************************************************************     > File Name: redis_subscriber.cpp     > Author: chenzengba     > Mail: chenzengba@gmail.com      > Created Time: Sat 23 Apr 2016 10:15:09 PM CST     > Description:   ************************************************************************/     #include <stddef.h>  #include <assert.h>  #include <string.h>  #include "redis_subscriber.h"    CRedisSubscriber::CRedisSubscriber():_event_base(0), _event_thread(0),  _redis_context(0)  {  }    CRedisSubscriber::~CRedisSubscriber()  {  }    bool CRedisSubscriber::init(const NotifyMessageFn &fn)  {      // initialize the event      _notify_message_fn = fn;      _event_base = event_base_new();    // 建立libevent對象      if (NULL == _event_base)      {          printf(": Create redis event failed.\n");          return false;      }        memset(&_event_sem, 0, sizeof(_event_sem));      int ret = sem_init(&_event_sem, 0, 0);      if (ret != 0)      {          printf(": Init sem failed.\n");          return false;      }        return true;  }    bool CRedisSubscriber::uninit()  {      _event_base = NULL;            sem_destroy(&_event_sem);         return true;  }    bool CRedisSubscriber::connect()  {      // connect redis      _redis_context = redisAsyncConnect("127.0.0.1", 6379);    // 非同步串連到redis伺服器上,使用預設連接埠      if (NULL == _redis_context)      {          printf(": Connect redis failed.\n");          return false;      }        if (_redis_context->err)      {          printf(": Connect redis error: %d, %s\n",               _redis_context->err, _redis_context->errstr);    // 輸出錯誤資訊          return false;      }        // attach the event      redisLibeventAttach(_redis_context, _event_base);    // 將事件綁定到redis context上,使設定給redis的回調跟事件關聯            // 建立事件處理線程      int ret = pthread_create(&_event_thread, 0, &CRedisSubscriber::event_thread, this);      if (ret != 0)      {          printf(": create event thread failed.\n");          disconnect();          return false;      }        // 設定串連回調,當非同步呼叫串連後,伺服器處理串連請求結束後調用,通知調用者串連的狀態      redisAsyncSetConnectCallback(_redis_context,           &CRedisSubscriber::connect_callback);        // 設定中斷連線回調,當伺服器中斷連線後,通知調用者串連斷開,調用者可以利用這個函數實現重連      redisAsyncSetDisconnectCallback(_redis_context,          &CRedisSubscriber::disconnect_callback);        // 啟動事件線程      sem_post(&_event_sem);      return true;  }    bool CRedisSubscriber::disconnect()  {      if (_redis_context)      {          redisAsyncDisconnect(_redis_context);          redisAsyncFree(_redis_context);          _redis_context = NULL;      }        return true;  }    bool CRedisSubscriber::subscribe(const std::string &channel_name)  {      int ret = redisAsyncCommand(_redis_context,           &CRedisSubscriber::command_callback, this, "SUBSCRIBE %s",           channel_name.c_str());      if (REDIS_ERR == ret)      {          printf("Subscribe command failed: %d\n", ret);          return false;      }            printf(": Subscribe success: %s\n", channel_name.c_str());      return true;  }    void CRedisSubscriber::connect_callback(const redisAsyncContext *redis_context,      int status)  {      if (status != REDIS_OK)      {          printf(": Error: %s\n", redis_context->errstr);      }      else      {          printf(": Redis connected!");      }  }    void CRedisSubscriber::disconnect_callback(      const redisAsyncContext *redis_context, int status)  {      if (status != REDIS_OK)      {          // 這裡異常退出,可以嘗試重連          printf(": Error: %s\n", redis_context->errstr);      }  }    // 訊息接收回呼函數  void CRedisSubscriber::command_callback(redisAsyncContext *redis_context,      void *reply, void *privdata)  {      if (NULL == reply || NULL == privdata) {          return ;      }        // 靜態函數中,要使用類的成員變數,把當前的this指標傳進來,用this指標間接訪問      CRedisSubscriber *self_this = reinterpret_cast<CRedisSubscriber *>(privdata);      redisReply *redis_reply = reinterpret_cast<redisReply *>(reply);            // 訂閱接收到的訊息是一個帶三元素的數組      if (redis_reply->type == REDIS_REPLY_ARRAY &&      redis_reply->elements == 3)      {          printf(": Recieve message:%s:%d:%s:%d:%s:%d\n",          redis_reply->element[0]->str, redis_reply->element[0]->len,          redis_reply->element[1]->str, redis_reply->element[1]->len,          redis_reply->element[2]->str, redis_reply->element[2]->len);                    // 調用函數對象把訊息通知給外層          self_this->_notify_message_fn(redis_reply->element[1]->str,              redis_reply->element[2]->str, redis_reply->element[2]->len);      }  }    void *CRedisSubscriber::event_thread(void *data)  {      if (NULL == data)      {          printf(": Error!\n");          assert(false);          return NULL;      }        CRedisSubscriber *self_this = reinterpret_cast<CRedisSubscriber *>(data);      return self_this->event_proc();  }    void *CRedisSubscriber::event_proc()  {      sem_wait(&_event_sem);            // 開啟事件分發,event_base_dispatch會阻塞      event_base_dispatch(_event_base);        return NULL;  }





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.