摘要:的發(fā)布訂閱功能由等命令組成。發(fā)布與訂閱頻道名中國男籃戰(zhàn)勝了美國男籃,獲得了奧運(yùn)冠軍訂閱多個(gè)頻道則直接添加該數(shù)組子元素這里除了這條命令之外其它命令都不能使用留意我們接收消息的回調(diào)函數(shù)。那么將消息發(fā)送給模式的訂閱者。
Redis的發(fā)布訂閱功能由 PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令組成。
通過執(zhí)行SUBSCRIBE命令,客戶端可以訂閱一個(gè)或多個(gè)頻道從而成為這些頻道的訂閱者(subscriber),
當(dāng)有其它客戶端向被訂閱的頻道發(fā)送消息時(shí),頻道的所有訂閱者都能收到這條消息。
在下圖中客戶端A、客戶端B、客戶端C,分別訂閱了cctv.5這個(gè)頻道。這個(gè)時(shí)候某個(gè)客戶端執(zhí)行了如下這條命令:
PUBLICH "cctv.5" "中國男籃戰(zhàn)勝了美國男籃,獲得了奧運(yùn)冠軍"
此時(shí)訂閱了cctv.5這個(gè)頻道的所有客戶端都將收到這條消息。
除了訂閱頻道之外,客戶端還可以通過執(zhí)行PSUBSCRIBE命令訂閱一個(gè)或多個(gè)模式,從而成為這些模式的訂閱者。每當(dāng)有其他客戶端向某個(gè)頻道發(fā)送消息時(shí),消息不僅僅會發(fā)送給這個(gè)頻道的訂閱者,還會發(fā)送給與這個(gè)頻道相匹配的模式訂閱者。
上圖中,我們給cctv.3這個(gè)頻道發(fā)送了一條消息"同一首歌",該消息首先會發(fā)送給它的訂閱者client A,然后根據(jù)模式匹配,cctv.3符合cctv.*這個(gè)模式。所以訂閱了cctv.*頻道的訂閱者也都可以收到消息呢。(●′?`●)?
頻道的訂閱
當(dāng)一個(gè)客戶端執(zhí)行SUBSCRIBE命令訂閱某個(gè)或某些頻道的時(shí)候,這個(gè)客戶端與被訂閱頻道之間就建立了一種訂閱關(guān)系。
Redis 將所有頻道的訂閱關(guān)系都保存在服務(wù)器狀態(tài)的pubsub_channels字典里面,這個(gè)字典的鍵是某個(gè)被訂閱的頻道,值是一個(gè)鏈表,鏈表里面記錄了所有訂閱這個(gè)頻道的客戶端。
客戶端執(zhí)行SUBSCRIBE命令訂閱某個(gè)或某些頻道的時(shí)候,服務(wù)器都會將客戶端與被訂閱的頻道在 pubsub_channels 字典中進(jìn)行關(guān)聯(lián)。
根據(jù)頻道是否已經(jīng)有其他訂閱者,關(guān)聯(lián)操作分為兩種情況執(zhí)行:
頻道已經(jīng)有其他訂閱者,那么在pubsub_channels字典中必然有相應(yīng)的訂閱者鏈表。程序唯一要做的是將客戶端添加到鏈表的末尾。
頻道沒有其它訂閱者,程序首先要在pubsub_channels字典中為頻道創(chuàng)建一個(gè)鍵,并將值設(shè)置為空鏈表,然后將客戶端添加到鏈表。成為鏈表的第一個(gè)元素。
php 發(fā)布與訂閱demo
// publish.php connect("127.0.0.1",6379); // 頻道名 $channel = "cctv.5"; $message = "中國男籃戰(zhàn)勝了美國男籃,獲得了奧運(yùn)冠軍"; $Redis->publish($channel,$message); ?> // subscribe.php connect("127.0.0.1",6379); $channel = ["cctv.5"]; // 訂閱多個(gè)頻道則直接添加該數(shù)組子元素 $Redis->subscribe($channel,function($instance,$channel,$message){ // 這里除了SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE這4條命令之外其它命令都不能使用 var_dump($instance,$channel,$message); }); ?>留意我們接收消息的回調(diào)函數(shù)。除了SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE這4條命令以外,其它命令都不能使用。
如果你使用的是CLI(命令行界面)此處是有bug的,你可能無法退訂消息。只能通過組合鍵Ctrl+c結(jié)束退訂。
退訂頻道
使用UNSUBSCRIBE命令可以退訂某個(gè)或某些頻道。服務(wù)器將從pubsub_channels中解除客戶端與被退訂頻道之間的關(guān)聯(lián):
程序會根據(jù)被退訂頻道的名字、在pubsub_channels字典中找到頻道對應(yīng)的訂閱者鏈表,然后從訂閱者鏈表中刪除退訂客戶端的信息。
如果刪除了客戶端之后,頻道的訂閱者鏈表變成了空鏈表,那么說明這個(gè)頻道已經(jīng)沒有任何的訂閱者了,程序?qū)?b>pubsub_channels字典中刪除頻道對應(yīng)的鍵。
訂閱模式
服務(wù)器將所有的訂閱關(guān)系都保存在服務(wù)器狀態(tài)的pubsub_channels屬性里面,在模式訂閱里服務(wù)器也將所有模式的訂閱關(guān)系都保存在服務(wù)器狀態(tài)的pubsub_patterns屬性里面。
struct redisServer { // ... // 保存所有模式訂閱關(guān)系 list *pubsub_patterns; // ... }
pubsub_patterns 屬性是一個(gè)鏈表,鏈表中的每個(gè)節(jié)點(diǎn)都包含著一個(gè)pubsubPattern結(jié)構(gòu),這個(gè)結(jié)構(gòu)的pattern屬性記錄了被訂閱的模式,而client屬性則記錄了訂閱模式的客戶端。
typedef struct pubsubPattern { // 訂閱模式的客戶端 redisClient *client; // 被訂閱的模式 robj * pattern; } pubsubPattern;
每當(dāng)客戶端執(zhí)行PSUBSCRIBE命令訂閱某個(gè)或某些模式的時(shí)候,服務(wù)器會對每個(gè)被訂閱的模式執(zhí)行以下兩個(gè)操作:
新建一個(gè)pubsubPattern結(jié)構(gòu),將結(jié)構(gòu)的pattern屬性設(shè)置為被訂閱的模式(如:music.*),client 屬性設(shè)置為訂閱模式的客戶端。
將pubsubPattern結(jié)構(gòu)添加到pubsub_patterns鏈表的表尾。
退訂模式
模式的退訂命令PUNSUBSCRIBE是PSUBSCRIBE命令的反操作。當(dāng)一個(gè)客戶端退訂某個(gè)或某些模式的時(shí)候,服務(wù)器將在pubsub_patterns鏈表中查找并刪除那些pattern屬性為退訂模式并且client屬性為執(zhí)行退訂命令的客戶端的pubsubPattern結(jié)構(gòu)。
發(fā)送消息
redis客戶端執(zhí)行 PUBLISH
將消息發(fā)送給頻道的所有訂閱者。
如果有一個(gè)或多個(gè)模式與頻道相匹配。那么將消息發(fā)送給pattern模式的訂閱者。
第一個(gè)操作的偽代碼:
def channel_publish(channel,message): /* 如果channel鍵不存在pubsub_channels字典中 那么說明channel頻道沒有任何訂閱者 程序不做發(fā)送動作直接返回 */ if channel not in server.pubsub_channels: return /* 運(yùn)行到這里,說明channel頻道至少有一個(gè)訂閱者 程序?qū)⒈闅vchannel頻道的訂閱者列表 將消息發(fā)送給所有訂閱者 */ for subscriber in server.pubsub_channels[channel]: send_message(subscriber,message)
第二個(gè)操作,因?yàn)榉?wù)器狀態(tài)中的pubsub_patterns鏈表記錄了所有模式的訂閱關(guān)系,所以為了將消息發(fā)送給所有與channel頻道相匹配的模式的訂閱者,PUBLISH命令要做的就是遍歷整個(gè)pubsub_patterns鏈表,查找那些模式相匹配的訂閱者。
def pattern_publish(channel,message): # 遍歷所有模式訂閱消息 for pubsubPattern in server.pubsub_patterns: # 如果頻道和模式相匹配 if(match(channel,pubsubPatter.pattern)): # 那么將消息發(fā)送給訂閱該模式的客戶端 send_message(pubsubPattern.client,message)
最后PUBLISH命令可以用一下偽代碼來描述:
def publish(channel,message): # 將消息發(fā)送給channel頻道的所有訂閱者 channel_publish(channel,message) #將消息發(fā)送給所有和channel 頻道相匹配的模式的訂閱者 pattern_publish(channel,message)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/23300.html
摘要:上一篇文章實(shí)戰(zhàn)第三章命令第五節(jié)有序集合下一篇文章實(shí)戰(zhàn)第三章命令第七節(jié)其他命令一般來說,發(fā)布與訂閱又稱的特點(diǎn)是訂閱者負(fù)責(zé)訂閱頻道,發(fā)送者負(fù)責(zé)向頻道發(fā)送二進(jìn)制字符串消息。到目前為止,本書介紹的大多數(shù)命令都是與特定數(shù)據(jù)類型相關(guān)的。 上一篇文章:Python--Redis實(shí)戰(zhàn):第三章:Redis命令:第五節(jié):有序集合下一篇文章:Python--Redis實(shí)戰(zhàn):第三章:Redis命令:第七節(jié):其...
摘要:中的發(fā)布訂閱模型是一種消息通信模式,今天聊一下在中實(shí)現(xiàn)簡單的發(fā)布訂閱功能。參考自鏈接描述以上就是發(fā)布訂閱的簡單實(shí)現(xiàn),如有錯(cuò)誤,歡迎交流指正 redis中的發(fā)布/訂閱模型是一種消息通信模式,今天聊一下在python中實(shí)現(xiàn)簡單的發(fā)布訂閱功能。 實(shí)現(xiàn)方式一: redis_helper.py: 封裝發(fā)布訂閱方法 import redis ...
閱讀 2661·2021-11-11 16:55
閱讀 1292·2021-09-22 15:25
閱讀 1809·2019-08-29 16:26
閱讀 995·2019-08-29 13:21
閱讀 2318·2019-08-23 16:19
閱讀 2806·2019-08-23 15:10
閱讀 790·2019-08-23 14:24
閱讀 1863·2019-08-23 13:48