zoukankan      html  css  js  c++  java
  • PHP共享内存的应用shmop系列

    简单的说明

    可能很少情况会使用PHP来操控共享内存,一方面在内存的控制上,MC已经提供了一套很好的方式,另一方面,自己来操控内存的难度较大,内存的读写与转存,包括后面可能会用到的存储策略,要是没有一定计算机组成原理的基础,想做这些不是一件容易的事情。那为什么还要使用它呢?如果我想进行管道通信,为其它的应用服务准备数据;我想建立自己的数据缓存体系,使用MC有点大炮打苍蝇的感觉。那么shmop会是一个选择,当然,在操作内存前,一定要谨慎。

    系统要求

    shmop系列函数只是在unix/Linux下可用,可以通过命令:

    Plain代码 
    1. ipcs -m  


    来查看当前的共享内存使用情况。其中,各个部分解释如下:

    key :共享内存的唯一的key值,共享内存通过该key来判断你读取的是哪一块内存。

    shmid:当使用key来获取内存时,你获得的是这个id的值。它作为你操作内存块的标识。

    owner:创建该共享内存块的用户

    perms:该共享内存的读写权限,8禁止,可以是777,与文件的读写权限一致。

    bytes:该内存块的大小

    nattch:连接该内存块的进程数

    status:当前状态,如:dest,即将删除等。

    使用示例

    具体的使用说明,在PHP手册中有详细介绍,这里不进行赘述。这里将写一些简单的操作例子。

    写入

    Php代码 
    1. <?php  
    2. /** 
    3.   * SHMOP共享内存操作示例 
    4.   * @author monkee 
    5.  **/  
    6. $key = 0x4337b700;  
    7. $size = 4096;  
    8. $shmid = @shmop_open($key, 'c', 0644, $size);  
    9. if($shmid === FALSE){  
    10.     exit('shmop_open error!');  
    11. }  
    12.   
    13. $data = '世界,你好!我将写入很多的数据,你能罩得住么?';  
    14.   
    15. $length = shmop_write($shmid, pack('a*',$data), 0);  
    16. if($length === FALSE){  
    17.     exit('shmop_write error!');  
    18. }  
    19.   
    20. @shmop_close($shmid);  
    21.   
    22. exit('succ');  
    23. ?>  

    读取

    Php代码 
    1. <?php  
    2. /** 
    3.   * SHMOP共享内存操作示例 
    4.   * @author monkee 
    5.  **/  
    6. $key = 0x4337b700;  
    7. $size = 256;  
    8. $shmid = @shmop_open($key, 'c', 0644, $size);  
    9. if($shmid === FALSE){  
    10.     exit('shmop_open error!');  
    11. }  
    12.   
    13. $data = unpack('a*', shmop_read($shmid, 0, 256));  
    14. if($data === FALSE){  
    15.     exit('shmop_read error!');  
    16. }  
    17. @shmop_close($shmid);  
    18.   
    19. exit($data[1]);  
    20. ?>  


    这里使用到了函数:pack() 这个函数用来将内存里的内容转化为二进制内容,具体请查看手册内容。

    多服务器内存同步

    已经在本地做好了这个服务,现在需要在多台服务器上进行内存数据同步。虽然这个时候可以放弃共享内存的方式来处理数据了,然而你被要求需要这么做。于是,同步我想不是问题,做好“主-从”的架构,我同步好的内存及时推送过去就可以了。然而,我是不是需要在从机上做一个监听程序呢?这样的代价有点大,好的一点是,从机上有apache。也就是说可以使用HTTP协议来进行通信了。

    同步策略

    如何同步?看似无聊的问题,却又产生了疑惑。同步数据呗,但是同步什么数据!一种方式是主机的内存改变后,程序读取所有内存数据然后发送到从机进行同步;如果我只是更改一些简单的操作位的话,那么小的更新却要引起整个内存块的同步,似乎有些浪费。还有一种,是更新变化。将变化进行更新。这种比较复杂,因为你需要定义每一种操作的处理。幸运的是,你需要操作的数据并不多,还有,你要定义的操作也不多:write,delete(read可以不要,因为你很少会从从机上读取数据)。那么好了,我们选择其中一种来做吧。

    主机发送

    Php代码 
    1. <?php  
    2.   
    3. /**  
    4.   * 共享内存操作,支持远程内存同步。 
    5.   * @author hufeng@ 
    6.   * @since 2011-08-10 
    7.   * 
    8.   */  
    9. define('PSHMOP_HOST', '192.168.0.1');   
    10. define('PSHMOP_SEPE', " ----------CKSJFIOWKJDFOCKJVNBBSDF---------- ");  
    11. class Pshmop   
    12. {  
    13.     static private $data = array();  
    14.     static public function write($key, $offset, $data, $size = 0){   
    15.         $h = array('key' => $key, 'offset' => $offset, 'size' => $size, 'ac' => 'write');   
    16.         return self::add($h, $data);   
    17.     }   
    18.        
    19.     static public function del($key){   
    20.         $h = array('key' => $key, 'ac' => 'delete');   
    21.         return self::add($h);   
    22.     }  
    23.   
    24.     static private function add($dataheader, $databody=''){  
    25.         self::$data[] = serialize($dataheader)." ".$databody;   
    26.     }  
    27.    
    28.     static private function send(){   
    29.         $d = & self::$data;  
    30.         if(count($d) == 0){  
    31.             return ;   
    32.         }  
    33.         $http_entity_body = join(PSHMOP_SEPE, $d);  
    34.         $http_entity_length = strlen($http_entity_body);  
    35.         $fp = fsockopen(PSHMOP_HOST, 80, $errno, $error);   
    36.         if(!$fp){   
    37.             return -1;   
    38.         }   
    39.   
    40.         fputs($fp, "PUT /pshmop.php HTTP/1.1 ");   
    41.         fputs($fp, 'Host: '.PSHMOP_HOST." ");   
    42.         fputs($fp, "Content-Type: application/x-www-form-urlencoded ");   
    43.         fputs($fp, "Content-Length: {$http_entity_length} ");   
    44.         fputs($fp, "Connection: close ");   
    45.         fputs($fp, $http_entity_body . " ");   
    46.         $d = '';   
    47.         while(!feof($fp)){   
    48.             $d .= fgets($fp, 4096);   
    49.         }   
    50.         fclose($fp);   
    51.         return $d;   
    52.     }   
    53. }   


    使用的时候,进行:

    Php代码 
    1. Pshmop::write();  
    2. Pshmop::write();  
    3. Pshmop::write();  
    4. Pshmop::send();  


    PS:为了支持多个更新一次传递的原则,以上便是举例。

    从机监听

    Php代码 
    1. <?php  
    2.   
    3. /** 
    4.   * 共享内存远程处理类 
    5.   * 对从远端传输到的数据进行处理、内存同步更新 
    6.   * @author hufeng@ 
    7.   * @since 2011-08-11 
    8.   **/  
    9. define('RSHMOP_SEPE', " ----------CKSJFIOWKJDFOCKJVNBBSDF---------- ");  
    10. class Rshmop  
    11. {  
    12.     static public function run($data){  
    13.         $items = @explode(RSHMOP_SEPE, $data);  
    14.         if($items === NULL){  
    15.             return -1;  
    16.         }  
    17.         $result = array('succ' => 0, 'error' => 0);  
    18.         foreach($items as $k => $i){  
    19.             self::op($i) === 0 ? $result['succ']++ : $result['error']++;  
    20.             unset($items[$k]);  
    21.         }  
    22.         return $result;  
    23.     }  
    24.     static public function op($str){  
    25.         $p = strpos($str, " ");  
    26.         $header = @unserialize(substr($str, 0, $p));  
    27.         if($header === FALSE){  
    28.             return 'Data Format Error!';  
    29.         }  
    30.         $body = substr($str, $p+1);  
    31.         $shmid = null;  
    32.         if($header['size'] > 0){  
    33.             $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);  
    34.         }  
    35.         if(!$shmid){  
    36.             $cmd = "ipcs -m | grep '{$header['key']}'";  
    37.             $em = exec($cmd);  
    38.             $em = preg_replace('/ +/', ' ', $em);  
    39.             $ems = explode(' ', $em);  
    40.             $header['size'] = intval($ems[4]);  
    41.             if($header['size'] == 0){  
    42.                 if($headerreturn ['ac'] == 'delete'){  
    43.                     return 0;  
    44.                 }else{  
    45.                     return 'Param `size` required!';  
    46.                 }  
    47.             }  
    48.             $shmid = @shmop_open($header['key'], 'c', 0644, $header['size']);  
    49.         }  
    50.         if($header['ac'] == 'write'){  
    51.             shmop_write($shmid, $body, $header['offset']);  
    52.         }  
    53.         if($header['ac'] == 'delete'){  
    54.             shmop_delete($shmid);  
    55.         }  
    56.         shmop_close($shmid);  
    57.         return 0;  
    58.     }  
    59. }  


    如果遇到主机有而从机未有的数据块(可能由网络问题造成,也可以有其它解决办法),可以选择delete然后再进行其它操作。

    缓存使用的策略

    觉得使用MC代价有点高,可以自己来控制内存和使用。当然,小部分的数据可以容易使用,但是当数据多的时候,决定哪部分数据进入内存,哪部分数据进入硬盘都是值得商榷的。这也就是为什么要提策略。

    常见的策略无非是 FIFO,LUR,LAR等,但并不是说这些策略就是好的。实际情况中,根据具体的业务需求,来组织相应的策略。最常见的,我们是将从数据库查询时间长的、获取数据耗时(从其它机器上获取)、计算耗时的、需要及时使用的放入内存中。

    这部分的代码就不写了,希望有所帮助。

    转载自:http://tubaluer.iteye.com/blog/1349797 作者 tubaluer

  • 相关阅读:
    HDU 5273 Dylans loves sequence 暴力递推
    HDU 5285 wyh2000 and pupil 判二分图+贪心
    HDU 5281 Senior's Gun 贪心
    HDU 5651 xiaoxin juju needs help 逆元
    HDU 5646 DZY Loves Partition
    HDU 5366 The mook jong
    HDU 5391Z ball in Tina Town 数论
    HDU 5418 Victor and World 允许多次经过的TSP
    HDU 5642 King's Order dp
    抽屉原理
  • 原文地址:https://www.cnblogs.com/chengzhi59/p/6489820.html
Copyright © 2011-2022 走看看