Toggle navigation
首页
[
Markdown
]
**简单的说明** 可能很少情况会使用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代码** ```php <?php /** * SHMOP共享内存操作示例 * @author monkee **/ $key = 0x4337b700; $size = 4096; $shmid = @shmop_open($key, 'c', 0644, $size); if($shmid === FALSE){ exit('shmop_open error!'); } $data = '世界,你好!我将写入很多的数据,你能罩得住么?'; $length = shmop_write($shmid, pack('a*',$data), 0); if($length === FALSE){ exit('shmop_write error!'); } @shmop_close($shmid); exit('succ'); ?> ``` **读取Php代码** ```php <?php /** * SHMOP共享内存操作示例 * @author monkee **/ $key = 0x4337b700; $size = 256; $shmid = @shmop_open($key, 'c', 0644, $size); if($shmid === FALSE){ exit('shmop_open error!'); } $data = unpack('a*', shmop_read($shmid, 0, 256)); if($data === FALSE){ exit('shmop_read error!'); } @shmop_close($shmid); exit($data[1]); ?> ``` 这里使用到了函数: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', "rn----------CKSJFIOWKJDFOCKJVNBBSDF----------rn"); 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)."n".$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.1rn"); 41. fputs($fp, 'Host: '.PSHMOP_HOST."rn"); 42. fputs($fp, "Content-Type: application/x-www-form-urlencodedrn"); 43. fputs($fp, "Content-Length: {$http_entity_length}rn"); 44. fputs($fp, "Connection: closernrn"); 45. fputs($fp, $http_entity_body . "rnrn"); 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', "rn----------CKSJFIOWKJDFOCKJVNBBSDF----------rn"); 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, "n"); 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等,但并不是说这些策略就是好的。实际情况中,根据具体的业务需求,来组织相应的策略。最常见的,我们是将从数据库查询时间长的、获取数据耗时(从其它机器上获取)、计算耗时的、需要及时使用的放入内存中。这部分的代码就不写了,希望有所帮助。
[
Html
]