一、說明:
訂閱,取消訂閱和發布實現了發布/訂閱消息范式(引自wikipedia),發送者(發布者)不是計划發送消息給特定的接收者(訂閱者)。而是發布的消息分到不同的頻道,不需要知道什么樣的訂閱者訂閱。訂閱者對一個或多個頻道感興趣,只需接收感興趣的消息,不需要知道什么樣的發布者發布的。這種發布者和訂閱者的解耦合可以帶來更大的擴展性和更加動態的網絡拓撲。
二、發布及訂閱功能:
- 基於事件的系統中,Pub/Sub是目前廣泛使用的通信模型,它采用事件作為基本的通信機制,提供大規模系統所要求的松散耦合的交互模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;發布者(如服務器)可將訂閱者感興趣的事件隨時通知相關訂閱者。
- 消息發布者,即publish客戶端,無需獨占鏈接,你可以在publish消息的同時,使用同一個redis-client鏈接進行其他操作(例如:INCR等)
- 消息訂閱者,即subscribe客戶端,需要獨占鏈接,即進行subscribe期間,redis-client無法穿插其他操作,此時client以阻塞的方式等待“publish端”的消息;這一點很好理解,因此subscribe端需要使用單獨的鏈接,甚至需要在額外的線程中使用。
三、PUBLISH端代碼:
<?php /** * redis sub(消息訂閱端) * @date 2016-09-20 15:00 */ $redis = new Redis(); // 第一個參數為redis服務器的ip,第二個為端口 $res = $redis->connect('121.41.88.209', 6379); // test為發布的頻道名稱,hello,world為發布的消息 $res = $redis->publish('test','hello,world'.rand(00000,99999));
說明:發布一個名字叫test的頻道,信息是:hello,world
四、SUBSCRIBE端代碼:
<?php /** * redis sub(消息訂閱端) * @date 2016-09-20 15:00 */ $redis = new Redis(); $res = $redis->pconnect('121.41.88.209', 6379); $redis->setOption(\Redis::OPT_READ_TIMEOUT,-1); $redis->subscribe(array('test'), 'callback'); // 回調函數,這里寫處理邏輯 function callback($instance, $channelName, $message)
{ echo $channelName, "==>", $message,PHP_EOL; }
//ThinkPHP 使用
public function publish() { $redis = RedisInstance::getInstance(); $redis->publish('test','ThinkPHP browser output:'.date('Y-m-d H:i:s',time())); }
說明:已經訂閱到了剛才發布的 'ThinkPHP browser output'消息:
五、遇到的錯誤代碼:
在命令執行redis訂閱端腳本時,發現在終端會輸出:
PHP Fatal error: Uncaught exception 'RedisException' with message 'read error on connection' in …
這個錯誤大概的意思就是遇到了一個未捕獲的異常:RedisException,消息讀取錯誤當連接的時候。 應該是redis的客戶端讀取超時原因導致。 很多人在github上留言能不能提供一個類似php的pconnect的接口,但是貌似redis官方對這個沒有一個官方的解決辦法。
錯誤解決辦法(以下3種辦法):
【1】設置,default_socket_time = -1 但是本機測試的時候,應該是版本不一樣的原因,直接報錯:
redis server went away
【2】給redis connect的時候( pconnect( $host, $port = 6379, $timeout = 0.0 ))給timeout設置一個較大的值。
【3】通過Redis自帶的常量設置
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
六、模式匹配訂閱
Redis 的Pub/Sub實現支持模式匹配。
客戶端可以訂閱全風格的模式以便接收所有來自能匹配到給定模式的頻道的消息。 比如,將接收所有發到 test.name,test.phone,test.address...等等的消息,該這樣寫:
PUBSCRIBE test.*
說明:在終端回車后,同時再新的窗口里分別發布兩個頻道的消息,名字分別為:test.name和test.phone,然后切換到訂閱端的窗口里,結果如下圖所示:
由上圖可以看出,在訂閱了test.*頻道后,一共收到了 test.name和test.phone兩個頻道的消息,這就是模式匹配訂閱。
那么取消訂閱匹配該模式的客戶端也比較簡單:
PUNSUBSCRIBE test.*
參考地址:http://phping.sinaapp.com/blog/php-redis-sub-pub.html