消息通信(IPC)

       在PHP中使用共享内存段  在不一样的处理进程之间使用共享内存是一个实现不一样进程之间相互通信的好方法。若是你在一个进程中向所共享的内存写入一段信息,那么全部其余的进程也能够看 到这段被写入的数据。很是方便。 php

     在PHP中有了共享内存的帮助,你能够实现不一样进程在运行同一段PHP脚本时返回不一样的结果。或实现对PHP同时运行数量 的实时查询等等。共享内存容许两个或者多个进程共享一给定的存储区。由于数据不须要在*户机和*务器之间复制,因此这是最快的一种IPC。使用共享内存的惟一窍门是多个进程对一给定存储区的同步存取。 数组

     如何创建一个共享内存段呢?下面的代码能够帮你创建共享内存。$shm_id = shmop_open($key, $mode, $perm, $size);注意,每一个共享内存段都有一个惟一的ID, 在PHP中,shmop_open会把创建好的共享内存段的ID返回,这里咱们用$shm_id记录它。而$key是一个咱们逻辑上表示共享内存段的 Key值。不一样进程只要选择同一个Key id就能够共享同一段存储段。习惯上咱们用一个串(相似文件名同样的东西)的散列值做为key id. $mode指明了共享内存段的使用方式。 浏览器

     这里因为是新建,所以值为’c’ –取create之意。若是你是访问已经创建过的共享内存那么请用’a’,-- 取access之意。$perm参数定义了访问的权限,8进制,关于权限定义请看UNIX文件系统帮助。$size定义了共享内存的大小。尽管有点象 fopen(文件处理)你可不要当它同文件处理同样。后面的描述你将看到着一点。$shm_id = shmop_open(0xff3, "c", 0644, 100); 这里咱们打开了一个共享内存段 键值0xff3 –rw-r—r—格式,大小为100字节。若是须要访问已有的共享内存段,你必须在调用shmop_open中设第三、4个参数为0。 缓存

      IPC工做状态的查询 在Unix下,你能够用一个命令行程序ipcs查询系统全部的IPC资源状态。不过有些系统要求须要超级用户方能执行。下图是一段ipcs的运行结果。上图中系统显示了4个共享内存段,注意其中第4个键值为0x00000ff3的就是咱们刚刚运行过的PHP程序所建立的。关于ipcs的用法请参*UNIX用户手册。如何释放共享内存呢 释放共享内存的办法是调用PHP指令:shmop_delete($id) $id 就是你调用shmop_open所存的shmop_op的返回值。还有一个办法就是用UNIX的管理指令: ipcrm id, id就是你用ipcs看到的ID.和你程序中的$id不同。 服务器

     不过要当心,若是你用ipcrm直接删除共享内存段那么有可能致使其余不知道这一状况的进程在引用这个已经不复存在的共享内存器时出现一些不可预测的错误(每每结果不妙)。如何使用(读写)共享内存呢 使用以下所示函数向共享内存写入数据 int shmop_write (int shmid, string data, int offset) 其中shmid是用shmop_open返回的句柄。$Data变量存放了要存放的数据。$offset描述了写入从共享内存的开始第一个字节的位置(以0开始)。
网络

     读取操做是: string shmop_read (int shmid, int start, int count) 一样,指明$shmid,开始偏移量(以0开始)、总读取数量。返回结果串。这样,你就能够把共享内存段看成是一个字节数组。读几个再写几个,想干吗就干吗,十分方便。  多进程问题的*虑 如今,在单独的一个PHP进程中读写、建立、删除共享内存方面上你应该没有问题了。可是,显然实际运行中不可能只是一个PHP进程在运行中。若是在多个进 程的状况下你仍是沿用单个进程的处理方法,你必定会碰到问题 ---- 著名的并行和互斥问题。好比说有2个进程同时须要对同一段内存进行读写。当两个进程同时执行写入操做时,你将获得一个错误的数据,由于该段内存将之多是 最后执行的进程的内容,甚至是由2个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。 数据结构

      为了解决这个问题,咱们必须引入互斥机制。互斥 机制在不少操做系统的教材上都有专门讲述,这里很少重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另一种进程间通信(IPC)的方式,它同其余IPC机构(管道、FIFO、消息队列)不一样。 并发

      它是一个记数器,用于控制多进程对共享数据的存储。一样的是你能够用ipcs和ipcrm实现对信号灯使用状态的查询和对其实现删除操做。在PHP中你能够用下列函数建立一个新的信号量并返回操做该信号量的句柄。若是该key指向的信号量已经存在,sem_get直接返回操做该信号量的句柄。int sem_get (int key [, int max_acquire [, int perm]]) $max_acquire 指明同时最多能够用几个进程进入该信号而没必要等待该信号被释放(也就是最大同时处理某一资源的进程数目,通常该值均为一)。$perm指明了访问权限。一旦你成功的拥有了一个信号量,你对它所能作的只有2种:请求、释放。 socket

       当你执行释放操做时, 系统将把该信号值减一。若是小于0那就还设为0。而当你执行请求操做时,系统将把该信号值加一,若是该值大于设定的最大值那么系统将挂起你的处理进程直到 其余进程释放到小于最大值为止。通常状况下最大值设为1,这样一来当一个进程得到请求时其余后面的进程只能等待它退出互斥区后释放信号量才能进入该互斥区 并同时设为独占方式。这样的信号量常称为双态信号量。固然,若是初值是任意一个正数就代表有多少个共享资源单位可供共享应用。申请、释放操做的PHP格式以下:int sem_acquire (int sem_identifier) 申请  int sem_release (int sem_identifier) 释放 其中sem_identifier是调用sem_get的返回值(句柄)。正如你所看到的,互斥的实现很简单:申请进入临界区,对临界区资源进行操做(好比修改共享内存)退出临界区并释放信号。 tcp

       这样一来就能够保证在同一个时间片 中不可能有同时2个进程对同一段共享内存进行操做。由于信号量机制保证一个时间片只能由一个进程进入,其余进程必须等待当前处理的进程完成后方能进入。临界区通常是指那些不容许同时有多个进程并发处理的代码段。要注意的是:在PHP中必须由同一个进程释放它所占用的信号量。在通常系统中容许进程释放别的进程占用的信号。在编写临界区代码必定要当心设计资源的分配,避免A等B,B等A的死锁状况发生。

      IPC的运用是十分普遍的。好比,在不一样进程间保存一个解释过的复杂的配置文件、或具体设置的用户等,以免重复处理。我也曾经用共享内存的技术把一大批 PHP脚本必须引用的一个很大的文件放入共享内存,并由此显著提高了Web*务的速度、消除了部分瓶颈。关于它的使用还有聊天室,多路广播等等。IPC的 威力取决于你的想象力的大小。若是本文对你有一点点启发,那我不胜荣幸。愿意很你讨论这使人入迷的*脑技术。 


     Socket基础 产生一个*务器  产生一个客户端 在这一章里你将了解到迷人而又让人容易糊涂的套接字(Sockets)。Sockets在PHP中是没有充分利用的功能。今天你将看到产生一个能使用客户端链接的*务器,并在客户端使用socket进行链接,*务器端将详细的处理信息发送给客户端。当你看到完整的socket过程,那么你将会在之后的程序开发中使用它。这个服务器是一个能让你链接的HTTP服务器,客户端是一个Web浏览器,这是一个单一的 客户端/服务器 的关系。 PHP使用Berkley的socket库来建立它的链接。你能够知道socket只不过是一个数据结构。你使用这个socket数据结构去开始一个客户 端和服务器之间的会话。这个服务器是一直在监听准备产生一个新的会话。当一个客户端链接服务器,它就打开服务器正在进行监听的一个端口进行会话。这时,服 务器端接受客户端的链接请求,那么就进行一次循环。如今这个客户端就可以发送信息到服务器,服务器也能发送信息给客户端。产生一个Socket,你须要三个变量:一个协议、一个socket类型和一个公共协议类型。产生一个socket有三种协议供选择,继续看下面的内容来获取详细的协议内容。定义一个公共的协议类型是进行链接一个必不可少的元素。下面的表咱们看看有那些公共的协议类型。 表一:协议 名字/常量     描述
AF_INET  这是大多数用来产生socket的协议,使用TCP或UDP来传输,用在IPv4的地址
AF_INET6     与上面相似,不过是来用在IPv6的地址
AF_UNIX  本地协议,使用在Unix和Linux系统上,它不多使用,通常都是当客户端和服务器在同一台及其上的时候 SOCK_STREAM  这个协议是按照顺序的、可靠的、数据完整的基于字节流的链接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM  这个协议是无链接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的链接。
SOCK_SEQPACKET  这个协议是双线路的、可靠的链接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。SOCK_RAW  这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM  这个类型是不多使用的,在大部分的操做系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序 ICMP  互联网控制消息协议,主要使用在网关和主机上,用来检查网络情况和报告错误信息
UDP      用户数据报文协议,它是一个无链接,不可靠的传输协议
TCP 传输控制协议,这是一个使用最多的可靠的公共协议,它能保证数据包可以到达接受者那儿,若是在传输过程当中发生错误,那么它将从新发送出错数据包。如今你知道了产生一个socket的三个元素,那么咱们就在php中使用socket_create()函数来产生一个socket。这个 socket_create()函数须要三个参数:一个协议、一个socket类型、一个公共协议。socket_create()函数运行成功返回一个 包含socket的资源类型,若是没有成功则返回false。


Resourece socket_create(int protocol, int socketType, int commonProtocol);


如今你产生一个socket,而后呢?php提供了几个操纵socket的函数。你可以绑定socket到一个IP,监听一个socket的通讯,接受一个socket;如今咱们来看一个例子,了解函数是如何产生、接受和监听一个socket。上面这个例子产生一个你本身的服务器端。例子第一行,$commonProtocol = getprotobyname(“tcp”);
使用公共协议名字来获取一个协议类型。在这里使用的是TCP 公共协议,若是你想使用UDP或者ICMP协议,那么你应该把getprotobyname()函数的参数改成“udp”或“icmp”。还有一个可选的 办法是不使用getprotobyname()函数而是指定SOL_TCP或SOL_UDP在socket_create()函数中。以上全部的函数都是PHP中关于socket的,使用这些函数,你必须把你的socket打开,若是你没有打开,请编辑你的php.ini文件,去掉下面这行前面的注释:
extension=php_sockets.dll
若是你没法去掉注释,那么请使用下面的代码来加载扩展库:若是你不知道你的socket是否打开,那么你可使用phpinfo()函数来肯定socket是否打开。你经过查看phpinfo信息了解socket是否打开。以下图:
如今咱们把第一个例子进行完善。你须要监听一个指定的socket而且处理用户的链接。你应该使用你的命令提示符来运行这个例子。理由是由于这里将产生一个服务器,而不是一个Web页面。若是你尝试使用Web浏览器来运行这个脚本,那么颇有可能它会超过30秒的限时。你可使用下面的代码来设置一个无限的运行时间,可是仍是建议使用命令提示符来运行。
set_time_limit(0);
在你的命令提示符中对这个脚本进行简单测试:

Php.exe example01_server.php若是你没有在系统的环境变量中设置php解释器的路径,那么你将须要给php.exe指定详细的路径。当你运行这个服务器端的时候,你可以经过远程登录(telnet)的方式链接到端口1337来测试这个服务器。以下图:上面的服务器端有三个问题:1. 它不能接受多个链接。2. 它只完成惟一的一个命令。

3. 你不能经过Web浏览器链接这个服务器。

这个第一个问题比较容易解决,你可使用一个应用程序去每次都链接到服务器。可是后面的问题是你须要使用一个Web页面去链接这个服务器,这个比较困难。你可让你的服务器接受链接,而后些数据到客户端(若是它必定要写的话),关闭链接而且等待下一个链接。处理第二个问题是很容易的。你须要产生一个php页链接一个socket,发送一些数据进它的缓存并处理它。而后你又个处理后的数据在还顿,你可以发送你的数据到服务器。在另一台客户端链接,它将处理那些数据。这个例子的代码演示了客户端链接到服务器。客户端读取数据。若是这是第一时间到达这个循环的首次链接,这个服务器将发送“NO DATA”返回给客户端。若是状况发生了,这个客户端在链接之上。客户端发送它的数据到服务器,数据发送给服务器,客户端等待响应。一旦接受到响应,那么 它将把响应写到屏幕上。
相关文章
相关标签/搜索