layout: posttitle: PHP,Swoole,Redis list实现简单消息推送
subtitle: PHP,Swoole,Redis list实现简单消息推送
date: 2019-02-16
author: he xiaodong
header-img: img/default-post-bg.jpg
catalog: true
tags:
- PHP
- Redis
- Swoole
- Redis List
- 消息推送

主要是利用 Swoole 的 Redis 协程属性及 Redis list 的阻塞读,当 list 有新消息时, swoole redis 能获取到消息,推送给链接的 fd

swoole.html
用户端代码没有变,还是原来的聊天室页面,具体参见上篇文章

swoole.php

  1. <?php
  2. $server = new swoole_websocket_server("0.0.0.0", 9502);
  3. $server->on('workerStart', function ($server, $workerId) {
  4. $redis = new Swoole\Coroutine\Redis();
  5. $redis->connect('127.0.0.1', 6379);
  6. while (true) {
  7. // brpop 第二个参数 50 表示超时(阻塞等待)时间, blpop 同理,详情建议读文档,对应的 redis 操作是 rpush/lpush key content
  8. if (($message = $redis->brpop('message', 50)) === null) {
  9. continue;
  10. }
  11. // var_dump($message); 结果为数组
  12. foreach ($server->connections as $fd) {
  13. $server->push($fd, 'redis 的 ' . $message[0] . ' 队列发送消息:' . $message[1]);
  14. }
  15. }
  16. });
  17. $server->on('open', function ($server, $request) {
  18. $server->push($request->fd, "hello;\n");
  19. });
  20. $server->on('message', function (swoole_websocket_server $server, $request) {
  21. $server->push($request->fd, "hello");
  22. });
  23. $server->on('close', function ($server, $fd) {
  24. echo "client-{$fd} is closed\n";
  25. $server->close($fd);
  26. });
  27. $server->start();

方式如常:php swoole.php 启动 swoole 进程,然后通过浏览器访问 http://localhost/swoole.html , 新起终端,输入 redis-cli 进入 redis, 然后执行: rpush message xxx, 往 message list 中写入一个数据,swoole 监听着代码,然后就会自动打印数据并推送到 fd,效果如图:

2019-02-18-PHP,Swoole,Redis list实现消息推送 - 图1

进阶思考:以上的示例为向所有在线的 fd 推消息,如果一个用户登录之后,在 redis 的 hash 中保存用户 id 对应的 fd,而 list 的名称为 user_1_messages, 这样的名称,中间为用户具体 id, 则用户可以消费自己的队列数据,通知在 hash 中查找用户 id 对应的 fd 值,向对应的 fd 推消息。这样就算是一个较完整的简单消息消费系统了,有时间在写具体代码。

tips: 一次性推送多条数据,例如 rpush message content1 content2 content3, brpop 的顺序为 content3 content2 content1,则推送顺序也为 3 2 1

最后恰饭 阿里云全系列产品/短信包特惠购买 中小企业上云最佳选择 阿里云内部优惠券