首页 > 开发 > PHP > 正文

php实现redis的服务端的示例

2024-05-04 22:01:23
字体:大 中 小
来源:转载
供稿:网友

大家都知道redis是用C来实现的,现在我用php来实现一个简单的仅支持SET和GET命令的redis服务端,主要是为了更好的了解redis的服务端和php的网络编程.代码如下:

  1. /** 
  2.  * 多进程阻塞式 
  3.  */ 
  4. class Xtgxiso_server 
  5. { 
  6.     private $socket = false; 
  7.     private $process_num = 100; 
  8.     public $redis_kv_data = array(); 
  9.     public $onMessage = null; 
  10.  
  11.     function __construct($host="0.0.0.0",$port=1215) 
  12.     { 
  13.         $this->socket = stream_socket_server("tcp://".$host.":".$port,$errno, $errstr); 
  14.         if (!$this->socket) die($errstr."--".$errno); 
  15.         echo "listen $host $port /r/n"; 
  16.         ini_set("memory_limit", "128M"); 
  17.     } 
  18.  
  19.     private function parseRESP(&$conn){ 
  20.         $line = fgets($conn); 
  21.         if($line === '' || $line === false) 
  22.         { 
  23.             return null; 
  24.         } 
  25.         $type = $line[0]; 
  26.         $line = mb_substr($line,1,-2); 
  27.         switch ( $type ){ 
  28.             case "*": 
  29.                 $count = (int) $line; 
  30.                 $data = array(); 
  31.                 for ($i = 1; $i <= $count; $i++) { 
  32.                     $data[] = $this->parseRESP($conn); 
  33.                 } 
  34.                 return $data; 
  35.             case "$": 
  36.                 if ($line == '-1') { 
  37.                     return null; 
  38.                 } 
  39.                 $length = $line + 2; 
  40.                 $data = ''; 
  41.                 while ($length > 0) { 
  42.                     $block = fread($conn, $length); 
  43.                     if ($length !== strlen($block)) { 
  44.                         throw new Exception('RECEIVING'); 
  45.                     } 
  46.                     $data .= $block; 
  47.                     $length -= mb_strlen($block); 
  48.                 } 
  49.                 return mb_substr($data, 0, -2); 
  50.         } 
  51.         return $line; 
  52.     } 
  53.  
  54.     private function start_worker_process(){ 
  55.         $pid = pcntl_fork(); 
  56.         switch ($pid) { 
  57.             case -1: 
  58.                 echo "fork error : {$i} /r/n"; 
  59.                 exit; 
  60.             case 0: 
  61.                 while ( 1 ) { 
  62.                     echo  "waiting.../n"; 
  63.                     $conn = stream_socket_accept($this->socket, -1); 
  64.                     if ( !$conn ){ 
  65.                         continue; 
  66.                     } 
  67.                     //"*3/r/n$3/r/nSET/r/n$5/r/nmykey/r/n$7/r/nmyvalue/r/n" 
  68.                     while(1){ 
  69.                         $arr = $this->parseRESP($conn); 
  70.                         if ( is_array($arr) ) { 
  71.                             if ($this->onMessage) { 
  72.                                 call_user_func($this->onMessage, $conn, $arr); 
  73.                             } 
  74.                         }else if ( $arr ){ 
  75.                             if ($this->onMessage) { 
  76.                                 call_user_func($this->onMessage, $conn, $arr); 
  77.                             } 
  78.                         }else{ 
  79.                             fclose($conn); 
  80.                             break; 
  81.                         } 
  82.                     } 
  83.                 } 
  84.             default: 
  85.                 $this->pids[$pid] = $pid; 
  86.                 break; 
  87.         } 
  88.     } 
  89.  
  90.     public function run(){ 
  91.         for($i = 1; $i <= $this->process_num; $i++){ 
  92.             $this->start_worker_process(); 
  93.         } 
  94.  
  95.         while(1){ 
  96.             foreach ($this->pids as $i => $pid) { 
  97.                 if($pid) { 
  98.                     $res = pcntl_waitpid($pid, $status,WNOHANG); 
  99.  
  100.                     if ( $res == -1 || $res > 0 ){ 
  101.                         $this->start_worker_process(); 
  102.                         unset($this->pids[$pid]); 
  103.                     } 
  104.                 } 
  105.             } 
  106.             sleep(1); 
  107.         } 
  108.     } 
  109.  
  110. } 
  111. $server =  new Xtgxiso_server(); 
  112.  
  113. $server->onMessage = function($conn,$info) use($server){ 
  114.     if ( is_array($info) ){ 
  115.         if ( $info["0"] == "SET" ) { 
  116.             $key = $info[1]; 
  117.             $val = $info[2]; 
  118.             $server->redis_kv_data[$key] = $val; 
  119.             fwrite($conn, "+OK/r/n"); 
  120.         }else if ( $info["0"] == "GET" ){ 
  121.             $key = $info[1]; 
  122.             fwrite($conn, "$".strlen($server->redis_kv_data[$key])."/r/n".$server->redis_kv_data[$key]."/r/n"); 
  123.         }else{ 
  124.             fwrite($conn,"+OK/r/n"); 
  125.         } 
  126.     }else{ 
  127.         fwrite($conn,"+OK/r/n"); 
  128.     } //Vevb.com 
  129. }; 
  130.  
  131. $server->run(); 

通过如下命令来测试PHP实现的性能:

redis-benchmark -h 10.170.233.221 -p 1215 -t set -n 80000 -q

看来还是不错的,大家有兴趣可以再实现其他命令!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表