前言
一直在做swoole的websocket,之前是利用swoole的client->send()来使用,后来一直想用redis的订阅模式来实现(其实早就有人做了),今天来实现以下方法.
直接上代码
socket.php的核心文件
<?php
use socket\Predis;
require 'Predis.php';
class jieshou
{
public $server = null;
public $client = null;
function __construct()
{
$this->server = new Swoole\WebSocket\Server("0.0.0.0", 10086);
$this->server->set([
//心跳检测
'heartbeat_check_interval' => 60,
'heartbeat_idle_time' => 600,
//设置证书,实现wss连接
// 'ssl_cert_file' => $this->pwd.'pai.wanguo.net.crt',
// 'ssl_key_file' => $this->pwd.'pai.wanguo.net.key',
]);
$this->server->on('workerStart', [$this, 'onworkerStart']);
$this->server->on('message', [$this, 'onmessage']);
$this->server->on('close', [$this, 'onclose']);
$this->server->start();
}
/**
* 发送全部联系人
* @param $name
*/
public function push_all($name, $json)
{
foreach ($this->server->connections as $fd) {
$this->server->push($fd, $json);
}
}
/**
* 发送指定联系人
* @param $member_id
* @param $json
*/
public function push_one($name, $member_id, $json)
{
$value = Predis::getInstance()->hGet($name, $member_id);
$this->server->push($value, $json);
}
function onworkerStart($server, $workerId)
{
$this->client = new swoole_redis;
$this->client->on('message', [$this, 'onmessages']);
$this->client->connect('127.0.0.1', 6379, [$this, 'onconnect']);
}
function onconnect(swoole_redis $client, $result)
{
$client->subscribe('CCTV');
}
function onmessages(swoole_redis $client, $result)
{
// print_r($result);
$data = json_decode($result[2], true);
if (empty($data['member_id'])) {
$this->push_all('big', $result[2]);
} else {
$this->push_one('big', $data['member_id'], $result[2]);
}
}
function onmessage($server, $frame)
{
$data = json_decode($frame->data, true);
if (empty($data["member_id"])) {
return flase;
}
Predis::getInstance()->hSet('big', $data["member_id"], $frame->fd);
Predis::getInstance()->set($frame->fd, $data["member_id"]);
$data['mgs'] = '开始传递';
$this->push_all('big', json_encode($data));
}
function onclose($serv, $fd)
{
$key = Predis::getInstance()->get($fd);
Predis::getInstance()->hdel('big', $key);
Predis::getInstance()->del($fd);
}
}
new jieshou();
Predis.php(redis的单例模式)
<?php
/**
* Created by PhpStorm.
* User: asd
* Date: 2019/4/18
* Time: 10:19
*/
namespace socket;
class Predis
{
public $redis = '';
private static $channel = 'CCTV';
private static $_instance = null;
public static function getInstance()
{
if (empty(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct()
{
$this->redis = new \Redis();
$result = $this->redis->connect('127.0.0.1', 6379);
if ($result === false) {
throw new \Exception('redis connect error');
}
}
/**
* 设置哈希
* @param $name
* @param $key
* @param $value
* @return bool|int
*/
public function hSet($name, $key, $value)
{
return $this->redis->hSet($name, $key, $value);
}
/**
* @param $key
* @param $value
* @return bool
*/
public function set($key, $value)
{
return $this->redis->set($key, $value);
}
/**
* @param $key
* @return bool|string
*/
public function get($key)
{
return $this->redis->get($key);
}
/**
* @param $key
* @return int
*/
public function del($key)
{
return $this->redis->del($key);
}
/**
* 哈希获取值
* @param $name
* @param $key
* @return string
*/
public function hGet($name, $key)
{
return $this->redis->hGet($name, $key);
}
/**
* 哈希获取全部的value
* @param $name
*/
public function hVals($name)
{
return $this->redis->hVals($name);
}
/**
* 哈希删除指定的值
* @param $name
* @param $key
* @return bool|int
*/
public function hdel($name, $key)
{
return $this->redis->hdel($name, $key);
}
public function json($array = [])
{
$this->redis->publish(self::$channel, json_encode($array));
}
}
控制器中的调用
<?php
/**
* Created by PhpStorm.
* User: asd
* Date: 2019/4/18
* Time: 9:52
*/
namespace app\superacc\controller;
use controller\BasicAdmin;
use socket\Predis;
use app\superacc\model\Order;
use app\superacc\model\Member;
class Bigdata extends BasicAdmin
{
/**
* socket的状态
* 车主 che
* 用户 member
* 本月收益 this_month_money
* 上月收益 last_month_money
* 累计收益 money
*
*/
public function test()
{
$num = input('num');
$type = input('type');
$member_id = input('member_id');
$data = ['type' => $type, 'num' => $num, 'member_id' => $member_id];
Predis::getInstance()->json($data);
dd('success');
}
}
注意
还有一点需要注意的是,在关闭socket.php的时候,还有redis的异步监听回调也需要关闭,要不会出现莫名的一堆报错