本文轉載自連結:
<a href="http://blog.csdn.net/chenzba/article/details/51224715">http://blog.csdn.net/chenzba/article/details/51224715</a>
最近使用redis的c接口——hiredis,使用戶端與redis伺服器通信,實作消息訂閱和釋出(PUB/SUB)的功能,我把遇到的一些問題和解決方法列出來供大家學習。
廢話不多說,先貼代碼。
redis_publisher.h
redis_publisher.cpp
redis_subscriber.h
redis_subscriber.cpp:
hiredis提供了幾個異步通信的API,一開始根據API名字的了解,我們實作了跟redis伺服器建立連接配接、訂閱和釋出的功能,可在實際使用的時候,程式并沒有像我們預想的那樣,除了能夠建立連接配接外,任何事情都沒發生。
網上查了很多資料,原來hiredis的異步實作是通過事件來分發redis發送過來的消息的,hiredis可以使用libae、libev、libuv和libevent中的任何一個實作事件的分發,網上的資料提示使用libae、libev和libuv可能發生其他問題,這裡為了友善就選用libevent。hireds官網并沒有對libevent做任何介紹,也沒用說明使用異步機制需要引入事件的接口,是以一開始走了很多彎路。
關于libevent的使用這裡就不再贅述,詳情可以見libevent官網。
libevent官網:http://libevent.org/
libevent api文檔:https://www.monkey.org/~provos/libevent/doxygen-2.0.1/include_2event2_2event_8h.html#6e9827de8c3014417b11b48f2fe688ae
CRedisPublisher和CRedisSubscriber的初始化過程:
初始化事件處理,并獲得事件處理的執行個體:
在獲得redisAsyncContext *之後,調用
這樣就将事件處理和redis關聯起來,最後在另一個線程調用
啟動事件的分發,這是一個阻塞函數,是以,建立了一個新的線程處理事件分發,值得注意的是,這裡用信号燈_event_sem控制線程的啟動,意在程式調用
之後,能夠完全捕捉到這兩個回調。
有些人會覺得這兩個類設計有點備援,我們發現CRedisPublisher和CRedisSubscriber很多邏輯是一樣的,為什麼不把他們整合到一起成一個類,既能夠釋出消息也能夠訂閱消息。其實一開始我就是這麼幹的,在使用的時候發現,用同個redisAsynContex *對象進行消息訂閱和釋出,與redis服務連接配接會自動斷開,disconnect_callback回調會被調用,并且傳回奇怪的錯誤:ERR
only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context,是以,不能使用同個redisAsyncContext *對象實作釋出和訂閱。這裡為了減少設計的複雜性,就将兩個類的邏輯分開了。
當然,你也可以将相同的邏輯抽象到一個基類裡,并實作publish和subscribe接口。
編譯之前,需要安裝hiredis、libevent和boost庫,我是用的是Ubuntu x64系統。
hiredis官網:https://github.com/redis/hiredis
下載下傳源碼解壓,進入解壓目錄,執行make && make install指令。
libevent官網:http://libevent.org/下載下傳最新的穩定版
解壓後進入解壓目錄,執行指令
./configure -prefix=/usr
sudo make && make install
boost庫:直接執行安裝:sudo apt-get install libboost-dev
如果你不是用std::tr1::function的函數對象來給外層通知消息,就不需要boost庫。你可以用接口的形式實作回調,把接口傳給CRedisSubscribe類,讓它在接收到消息後調用接口回調,通知外層。
最後貼出例子代碼。
publisher.cpp,實作釋出消息:
subscriber.cpp實作訂閱消息:
關于編譯的問題:在g++中編譯,注意要加上-lhiredis -levent參數,下面是一個簡單的Makefile:
緻謝:
redis異步API使用libevent:http://www.tuicool.com/articles/N73uuu