🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
基于频道的实现方式主要通过以下三个命令: * `subscribe channel-1 channel-2`:订阅一个或者多个频道。 * `unsubscribe channel-1`:取消频道的订阅(命令操作界面上无法退订)。 * `publish channel-1 message`:向频道`channel-1`发送消息`message`。 打开一个客户端一,输入订阅命令`subscribe music movie`,表示当前客户端订阅了`music`和`movie`两个频道的消息: ![](https://img.kancloud.cn/48/dd/48dd4fda4654d2baabdeab6c61875907_595x182.png) 然后再打开一个客户端二,执行以下发布消息命令: ~~~sql publish movie myCountry //发布消息 myCountry 到 movie 频道 publish music love //发布消息 love 到 music 频道 publish tv myHome //发布消息 myHome 到 tv 频道 ~~~ ![](https://img.kancloud.cn/ce/de/cede9be83a57b07a2d3b19fc51e49505_621x149.png) 前面两个频道发布之后返回`1`就表示当前有`1`个客户端订阅了该频道,消息已经发送到这个客户端。 这时候我们再回到之前的客户端一,就会发现客户端一收到了`myCountry`和`love`两条消息,而`myHome`这条消息是属于频道`tv`,客户端一并没有订阅,故而不会收到: ![](https://img.kancloud.cn/8a/1c/8a1c5aeba43b8e399a2033bea0ce6868_688x273.png) 同时,还有以下`2`个命令可以查看当前客户端订阅的频道信息: * `pubsub channels [channel_name]`:查看当前服务器被订阅的频道。不带参数则返回所有频道,后面的参数可以使用通配符`?`或者`*`。 * `pubsub numsub channel_name [channel_name]`:查看指定频道的订阅数(可同时查看多个)。 #### 实现原理分析 客户端与其订阅的频道信息被保存在`redisServer`对象中的`pubsub_channels`属性中。 ~~~c struct redisServer { dict *pubsub_channels;//保存了客户端及其订阅的频道信息 //... 省略其他信息 }; ~~~ `pubsub_channels`属性是一个字典,其`key`值保存的就是频道名;`value`是一个链表,链表中保存的就是每个客户端的`id`,下图就是基于频道订阅的存储结构示意图: ![](https://img.kancloud.cn/f1/79/f1793aca4db3e068250771806313986d_771x231.png) * 订阅:订阅的时候首先会检查字典内是否存在这个频道:如果不存在,则需要为当前频道创建一个字典,同时创建一个链表作为`value`,并将当前客户端`id`放入链表;如果存在,则直接将当前客户端`id`放入链表末尾即可。 * 取消订阅:取消订阅的时候需要将客户端`id`从对应的链表中移除,如果移除之后链表为空,则需要同时将该频道从字典内删除。 * 发送消息:发送消息时首先会去`pubsub_channels`字典内寻找键,如果发现有可以匹配上的键,则会找到对应的链表,进行遍历发送消息。