You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
4.7 KiB
179 lines
4.7 KiB
<?php
|
|
ini_set("memory_limit", "128M");
|
|
/**
|
|
* redis 服务端
|
|
* 多进程阻塞式
|
|
* redis-benchmark -h 127.0.0.1 -p 11211 -t set -n 80000 -q
|
|
*
|
|
* @version 2.7.0
|
|
* @copyright 1997-2018 The PHP Group
|
|
* @author seatle <seatle@foxmail.com>
|
|
* @created time :2018-01-03
|
|
*/
|
|
class cls_redis_server
|
|
{
|
|
private $socket = false;
|
|
private $process_num = 3;
|
|
public $redis_kv_data = array();
|
|
public $onMessage = null;
|
|
|
|
public function __construct($host="0.0.0.0", $port=6379)
|
|
{
|
|
$this->socket = stream_socket_server("tcp://".$host.":".$port,$errno, $errstr);
|
|
if (!$this->socket) die($errstr."--".$errno);
|
|
echo "listen $host $port \r\n";
|
|
}
|
|
|
|
private function parse_resp(&$conn)
|
|
{
|
|
// 读取一行,遇到 \r\n 为一行
|
|
$line = fgets($conn);
|
|
if($line === '' || $line === false)
|
|
{
|
|
return null;
|
|
}
|
|
// 获取第一个字符作为类型
|
|
$type = $line[0];
|
|
// 去掉第一个字符,去掉结尾的 \r\n
|
|
$line = mb_substr($line, 1, -2);
|
|
switch ( $type )
|
|
{
|
|
case "*":
|
|
// 得到长度
|
|
$count = (int) $line;
|
|
$data = array();
|
|
for ($i = 1; $i <= $count; $i++)
|
|
{
|
|
$data[] = $this->parse_resp($conn);
|
|
}
|
|
return $data;
|
|
case "$":
|
|
if ($line == '-1')
|
|
{
|
|
return null;
|
|
}
|
|
// 截取的长度要加上 \r\n 两个字符
|
|
$length = $line + 2;
|
|
$data = '';
|
|
while ($length > 0)
|
|
{
|
|
$block = fread($conn, $length);
|
|
if ($length !== strlen($block))
|
|
{
|
|
throw new Exception('RECEIVING');
|
|
}
|
|
$data .= $block;
|
|
$length -= mb_strlen($block);
|
|
}
|
|
return mb_substr($data, 0, -2);
|
|
}
|
|
return $line;
|
|
}
|
|
|
|
private function start_worker_process()
|
|
{
|
|
$pid = pcntl_fork();
|
|
switch ($pid)
|
|
{
|
|
case -1:
|
|
echo "fork error : {$i} \r\n";
|
|
exit;
|
|
case 0:
|
|
while ( true )
|
|
{
|
|
echo "PID ".posix_getpid()." waiting...\n";
|
|
// 堵塞等待
|
|
$conn = stream_socket_accept($this->socket, -1);
|
|
if ( !$conn )
|
|
{
|
|
continue;
|
|
}
|
|
//"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n"
|
|
while( true )
|
|
{
|
|
$arr = $this->parse_resp($conn);
|
|
if ( is_array($arr) )
|
|
{
|
|
if ($this->onMessage)
|
|
{
|
|
call_user_func($this->onMessage, $conn, $arr);
|
|
}
|
|
}
|
|
else if ( $arr )
|
|
{
|
|
if ($this->onMessage)
|
|
{
|
|
call_user_func($this->onMessage, $conn, $arr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fclose($conn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
$this->pids[$pid] = $pid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public function run()
|
|
{
|
|
for($i = 1; $i <= $this->process_num; $i++)
|
|
{
|
|
$this->start_worker_process();
|
|
}
|
|
|
|
while( true )
|
|
{
|
|
foreach ($this->pids as $i => $pid)
|
|
{
|
|
if($pid)
|
|
{
|
|
$res = pcntl_waitpid($pid, $status,WNOHANG);
|
|
|
|
if ( $res == -1 || $res > 0 )
|
|
{
|
|
$this->start_worker_process();
|
|
unset($this->pids[$pid]);
|
|
}
|
|
}
|
|
}
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$server = new cls_redis_server();
|
|
$server->onMessage = function($conn, $info) use($server)
|
|
{
|
|
if ( is_array($info) )
|
|
{
|
|
$command = strtoupper($info[0]);
|
|
if ( $command == "SET" )
|
|
{
|
|
$key = $info[1];
|
|
$val = $info[2];
|
|
$server->redis_kv_data[$key] = $val;
|
|
fwrite($conn, "+OK\r\n");
|
|
}
|
|
else if ( $command == "GET" )
|
|
{
|
|
$key = $info[1];
|
|
$val = isset($server->redis_kv_data[$key]) ? $server->redis_kv_data[$key] : '';
|
|
fwrite($conn, "$".strlen($val)."\r\n".$val."\r\n");
|
|
}
|
|
else
|
|
{
|
|
fwrite($conn,"+OK\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fwrite($conn,"+OK\r\n");
|
|
}
|
|
};
|
|
$server->run();
|
|
|