問題已找到 $this->clearRedisCache(); 刪掉就沒事了 我不知道為什么會出現(xiàn)這個情況,如果加上 ,高并發(fā)時候 就會出現(xiàn)fd1 發(fā)送到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} 關(guān)閉連接\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 . "-待發(fā)送" . PHP_EOL;
if($this->server->isEstablished($fdId)) {
echo $fdId . "-發(fā)送成功" . 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那邊有連接池的試試
有可能是這個原因,我今天特地把代碼該刪的刪了,然后再試,還會出現(xiàn)變量被污染,當(dāng)并發(fā)高時候fd1 發(fā)送到fd2上去了,但是當(dāng)我把進(jìn)程改成1 ,就沒事了,話說不是有進(jìn)程隔離的嗎,怎么還會有這種情況出現(xiàn)呢
試了下,父進(jìn)程執(zhí)行到new Client
,不會建立鏈接,但$this->clearRedisCache();
這個在父進(jìn)程中會建立鏈接,導(dǎo)致后面建立的4個子進(jìn)程復(fù)用了父進(jìn)程的這個鏈接導(dǎo)致數(shù)據(jù)污染
,如果去掉這個$this->clearRedisCache();
,父進(jìn)程就沒有建立鏈接,每個子進(jìn)程接收請求的時候才會建立鏈接,所以數(shù)據(jù)不會污染 。
需要在WorkerStart里面初始化Redis連接。
$this->server->on('WorkerStart', function (\Swoole\Server $serv) {
//TODO 初始化Redis連接
});
$server = new Swoole\Server('0.0.0.0', 9502);
//必須在onWorkerStart回調(diào)中創(chuàng)建redis/mysql連接
$server->on('workerstart', function($server, $id) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$server->redis = $redis;
});
$server->on('receive', function (Swoole\Server $server, $fd, $reactor_id, $data) {
$value = $server->redis->get("key");
$server->send($fd, "Swoole: ".$value);
});
$server->start();