简单的说明

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

系统要求

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

  1. ipcs -m

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

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

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

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

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

bytes:该内存块的大小

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

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

使用示例

具体的使用说明,在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. $data = '世界,你好!我将写入很多的数据,你能罩得住么?';
  13. $length = shmop_write($shmid, pack('a*',$data), 0);
  14. if($length === FALSE){
  15. exit('shmop_write error!');
  16. }
  17. @shmop_close($shmid);
  18. exit('succ');
  19. ?>

读取

  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. $data = unpack('a*', shmop_read($shmid, 0, 256));
  13. if($data === FALSE){
  14. exit('shmop_read error!');
  15. }
  16. @shmop_close($shmid);
  17. exit($data[1]);
  18. ?>

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

多服务器内存同步

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

同步策略

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

主机发送

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

使用的时候,进行:

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

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

从机监听

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

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

缓存使用的策略

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

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

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

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

PHP共享内存的应用shmop系列的更多相关文章

  1. PHP共享内存详解

    前言 在PHP中有这么一族函数,他们是对UNIX的V IPC函数族的包装. 它们很少被人们用到,但是它们却很强大.巧妙的运用它们,可以让你事倍功半. 它们包括: 信号量(Semaphores) 共享内 ...

  2. php简单使用shmop函数创建共享内存减少服务器负载

    在之前的一篇博客[了解一下共享内存的概念及优缺点]已经对共享内存的概念做了说明.下面就来简单使用共享内存(其实也可以用其他工具,比如redis) PHP做内存共享有两套接口.一个是shm,它实际上是变 ...

  3. c/c++ linux 进程间通信系列4,使用共享内存

    linux 进程间通信系列4,使用共享内存 1,创建共享内存,用到的函数shmget, shmat, shmdt 函数名 功能描述 shmget 创建共享内存,返回pic key shmat 第一次创 ...

  4. 作为phper既然了解共享内存函数shmop的使用方法,那么就必须要了解一下信号量是什么,以及信号量使用的代码案例

    在单独的一个PHP进程中读写.创建.删除共享内存方面上你应该没有问题了.但是实际运行中不可能只是一个PHP进程在运行中.如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题--著名的并 ...

  5. 给PHP开启shmop扩展实现共享内存

    在项目开发中,想要实现PHP多个进程之间共享数据的功能,让客户端连接能够共享一个状态,需要开启共享内存函数shmop.如果预期考虑会遇到这方面需求,那么最好在编译PHP的时候添加--with-shmo ...

  6. POSIX 共享内存和 系列函数

    在前面介绍了system v 共享内存的相关知识,现在来稍微看看posix 共享内存 和系列函数. 共享内存简单来说就是一块真正的物理内存区域,可以使用一些函数将这块区域映射到进程的地址空间进行读写, ...

  7. php 共享内存学习(shmop函数)

    问题:希望可以在进程间共享变量,为共享数据提供快速访问 解决方案:除了可以使用APC模块,还可以用shmop或System V共享内存 //创建键 //将一个可访问的文件路径名转换为一个可供 shmo ...

  8. 【VxWorks系列】任务间同步与通信之共享内存

    在开始之前先说明三个概念,任务间的同步,互斥,通信. 同步,是指一个任务等待某个条件发生,而另外一个任务引发这个条件后,等待的任务会被触发执行相应的处理.这就是一个任务与另一任务之间的同步控制. 互斥 ...

  9. php操作共享内存shmop类及简单使用测试(代码)

    SimpleSHM 是一个较小的抽象层,用于使用 PHP 操作共享内存,支持以一种面向对象的方式轻松操作内存段.在编写使用共享内存进行存储的小型应用程序时,这个库可帮助创建非常简洁的代码.可以使用 3 ...

随机推荐

  1. 奇怪的Unrooted Tests错误

    错误如图: 条件如下: Eclipse里的Maven工程. 使用JUnit4(这个是否必须不知,反正我的工程用的4) 修改某个Test类里的方法名,或者增加一个Test方法. 现象: 在MyEclip ...

  2. python_35_进度条

    import sys for i in range(50): sys.stdout.write("+")#此命令不会像print语句执行一次,换行一次\ sys.stdout.fl ...

  3. 在maven项目中 配置代理对象远程调用crm

    1 在maven项目中配置代理对象远程调用crm 1.1 在项目的pom.xml中引入CXF的依赖 <dependency> <groupId>org.apache.cxf&l ...

  4. Jquery LigerUI

    http://www.ligerui.com/index.aspx http://api.ligerui.com/ 分享一个基于ligerui的系统应用案例ligerRM V2(权限管理系统)(提供下 ...

  5. Oracle 配置文件目录

    Oracle 配置文件目录 ① 在oracle安装目录下,找D:\oracle\product\10.2.0\client_1\NETWORK\ADMIN中的tnsnames.ora文件,找到之后,配 ...

  6. Java十进制转成二进制 八进制 十六进制

    int a = 357;//十进制转成二进制System.out.println(Integer.toBinaryString(a)); package com.swift; import java. ...

  7. SummerVocation_Leaning--java动态绑定(多态)

    概念: 动态绑定:在执行期间(非编译期间)判断所引用的对象的实际类型,根据实际类型调用其相应的方法.如下例程序中,根据person对象的成员变量pet所引用的不同的实际类型调用相应的方法. 具体实现好 ...

  8. redis 设置密码验证

    1.找到配置文件:如/etc/redis/redis.conf 2.找到以下内容 # requirepass foobared 3.修改为(redispassword是密码) requirepass ...

  9. 正则python正则,提取\t\n里面的大写英文字母

    ss = '['\r\n\t\t\t\t\t\t\t\t\t', '\r\n\t\t\t\t\t\t\t', '\r\n\t\t\t\t\t\t\t\t\tCMA CGM JACQUES JOSEPH ...

  10. Python 文件读写 文件和路径

    1.在Windows上,使用倒斜杆作为文件夹之间的分隔符,在Linux上,使用正斜杠作为路径分隔符.在编写Python脚本时,可以os.path.join()函数来处理 在Windows环境下命令如下 ...