这里使用nodejs的redis模块说明,具体可见https://www.npmjs.com/package/redis,先来通过一个简单的例子了解下redis中的Pub/Sub具体怎么实现吧。。
var express = require(‘express‘); var router = express.Router(); var redis = require("redis"); /* GET home page. */ router.get(‘/‘, function(req, res, next) { var client1 = redis.createClient(); var client2 = redis.createClient(6379,"192.168.20.132"); var msg_count = 0; client1.on("error", function (err) { console.log("Error " + err); }); client2.on("error",function(err){ console.log(err); }); client1.on("subscribe", function (channel, count) { //channel为订阅的事件类型(通道),count为当前客户端订阅的channel总数 client2.publish("a nice channel", "I am sending a message."); client2.publish("a nice channel", "I am sending a second message."); client2.publish("a nice channel", "I am sending my last message."); console.log("client1 sub count:" + count); console.log("client1 sub channel:" + channel); }); client1.on("message", function (channel, message) { //channel为send端所发送的订阅类型,message为该channel中所收到的信息 console.log("client1 channel name: " + channel + "->message: " + message); msg_count += 1; if (msg_count === 3) { client1.unsubscribe(); //退订所有channel client1.end(); //client1退出Pub/Sub模式,可继续执行其它redis命令 client2.end(); } }); client1.subscribe("a nice channel"); //自动触发"sunscribe"事件 res.render(‘index‘, {title: ‘Express‘}); }); module.exports = router;
将上述代码保存为index.js文件,替换Express项目中的index.js,然后启动后浏览器中输入:localhost:3000,观察Webstorm中打印信息如下:
client1 sub count:1 client1 sub channel:a nice channel client1 channel name: a nice channel->message: I am sending a message. client1 channel name: a nice channel->message: I am sending a second message. client1 channel name: a nice channel->message: I am sending my last message.
这里来说明下:
- require来redis模块后,通过redis的createClient方法创建 redis客户端连接,该方法可以指定三个参数,分别为:连接的redis server端口、server ip及可配置的options。不带任何参数时默认连接本机redis server的6379端口,编码时也可使用createClient(6379,"ip address",{})的options为空的形式使用默认配置,当然也可直接省略options对象
- error事件为client端操作报错时自动触发的事件
- subscribe事件和message事件稍后说明
发布订阅?
redis中的发布订阅,自我的理解是:发布订阅就是有一端发布消息,一端订阅消息即接收消息,这里的发布订阅端都可以称为client端,也就是说一个client既可以发布多个消息,亦可以订阅多个消息。
说 到消息,到底什么是消息?redis中的每条消息是一条带有三个元素的多条批量回复(multi-bulk-reply)。这货刚听时候着实难以理解,下 面继续。这里的第一个元素是消息类型,redis中消息类型并非我们理解的String、Object等,而是subscribe、 unsubscribe、message等类型。
- subscribe:如果类型为subscribe,则表示当前客户端成功订阅 了第二个元素所示频道(频道可以理解为消息的名称或channel,因为redis中client端发布消息后,redis server端再根据其它客户端是否订阅该名称或channel而转发该消息至订阅端),这时信息的第三个元素则记录了目前客户端已订阅频道的总数
- unsubscribe:表示当前客户端成功地退订了信息第二个元素所指示的频道。 信息的第三个元素记录了客户端目前仍在订阅的频道数量。 当客户端订阅的频道数量降为
0
时, 客户端不再订阅任何频道, 它可以像往常一样, 执行任何 Redis 命令 - message:表示这条信息是由某个客户端执行 PUBLISH命令所发送的, 真正的信息。 信息的第二个元素是信息来源的频道, 而第三个元素则是信息的内容
如果客户端执行以下命令:
redis> SUBSCRIBE first second
表明该客户端订阅了名称为first和second的两个channel,那么它将收到以下回复:
1) "subscribe" 2) "first" 3) (integer) 1 1) "subscribe" 2) "second" 3) (integer) 2
其中,subscribe表明此消息类型,first为channel名称,(integer) 1表示当前客户端订阅的channel总数为1,如果此时另一个客户端执行了如下命令:
redis> PUBLISH second Hello
表示该客户端发布了一个channel为second,内容为hello的一条信息,那么之前订阅了channel为second的客户端将收到以下信息:
1) "message" 2) "second" 3) "hello"
其中,message表明该消息为另一客户端发送而来,second为channel名,此时hello为信息内容。如果这时订阅的客户端再执行以下命令:
redis> UNSUBSCRIBE 表明订阅者退订所有之前订阅的channel,这时命令执行后收到回复如下:
1) "unsubscribe" 2) "second" 3) (integer) 1 1) "unsubscribe" 2) "first" 3) (integer) 0
可以看到消息退订时是一条条挨个退订,而且是“后订先退”顺序,当然也可以直接指定退订的channel。
有一点觉得比较重要:
通过PUBLISH发出去的信息,是不会保存在服务端的,服务端只是做中转处理。也就是说,如果客户端PUBLISH了信息至channel,而没有其它客户端订阅该channel,那么该消息也是无效的,消息的传递是以channel为载体的。