问题已找到 $this->clearRedisCache(); 删掉就没事了 我不知道为什么会出现这个情况,如果加上 ,高并发时候 就会出现fd1 发送到fd2里面,但是只是定义了一个清理redis的方法啊
<?php
require __DIR__ . '/vendor/predis/predis/autoload.php';
require __DIR__ . '/app/functions.php';
use Predis\Client;
class WebSocket{
private $server;
private $redis;
private $host = '127.0.0.1:6379?read_write_timeout=0';
public function __construct(){
$this->redis = new Client('tcp://'.$this->host);
//重新启动时删除所有redis缓存
$this->clearRedisCache();
$this->server = new Swoole\WebSocket\Server("0.0.0.0", 8088);
echo 'websocket ...' . PHP_EOL;
$this->server->set([
'worker_num' => 4
]);
$this->server->on('open', function (Swoole\WebSocket\Server $server, $request) {
$fd = $request->fd;
$param = $request->get;
$dmId = $param['id'] ?? 0;
$redisKey1 = "lottery-swoole-".$dmId;
$this->redis->setex($redisKey1,3600*24,$fd);
$this->redis->setex('websocket-id' . $fd,3600 * 24,$redisKey1);
$this->server->push($fd,json_encode([
'action' => 'heartbeat',
'mess' => '连接心跳'
]));
});
$this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
});
$this->server->on('close', function ($ser, $fd) {
echo "{$fd} 关闭连接\n";
$redisKey3 = $this->redis->get('websocket-id' . $fd);
if($redisKey3){
$this->redis->del($redisKey3);
$this->redis->del('websocket-id' . $fd);
}
});
$this->server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
$dm_id = $request->get['dm_id'] . PHP_EOL;
$redisKey4 = trim("lottery-swoole-" . $dm_id);
$data = [
'id' => (int)$request->get['uid'],
'nickname' => $request->get['nickname'],
'img' => $request->get['img']
];
$fdId = $this->redis->get($redisKey4);
if($fdId){
echo $fdId . "-待发送" . PHP_EOL;
if($this->server->isEstablished($fdId)) {
echo $fdId . "-发送成功" . PHP_EOL;
$this->server->push($fdId, json_encode($data));
}
}
$response->header('Content-Type', 'text/html; charset=utf-8');
$response->end('success');
});
$this->server->start();
}
private function clearRedisCache(){
$patterns = ['dm-swoole-*', 'lottery-swoole-*', 'websocket-id*'];
foreach ($patterns as $pattern) {
$this->deleteRedisKeys($pattern);
}
}
private function deleteRedisKeys($pattern) {
$keys = $this->redis->keys($pattern);
foreach ($keys as $key) {
$this->redis->del($key);
}
}
}
new WebSocket();
use Predis\Client;
这个客户端换成swoole那边有连接池的试试有可能是这个原因,我今天特地把代码该删的删了,然后再试,还会出现变量被污染,当并发高时候fd1 发送到fd2上去了,但是当我把进程改成1 ,就没事了,话说不是有进程隔离的吗,怎么还会有这种情况出现呢
删后的代码发出来看看
大佬 ,删除后的代码已经贴上去了 ,问题帮我看看,就是第17行,我不知道这个为什么会影响这么大
$this->clearRedisCache(); 这一行
试了下,父进程执行到
new Client
,不会建立链接,但$this->clearRedisCache();
这个在父进程中会建立链接,导致后面建立的4个子进程复用了父进程的这个链接导致数据污染
,如果去掉这个$this->clearRedisCache();
,父进程就没有建立链接,每个子进程接收请求的时候才会建立链接,所以数据不会污染 。需要在WorkerStart里面初始化Redis连接。
还有这种情况啊,我现在改成单进程了,问题解决了,先这样吧,谢谢了,还是这个论坛活跃些,那边 我的帖子还没过审核