当前位置: 首页 > Linux

php进程通信--SystemV消息队列

时间:2023-04-06 22:05:08 Linux

在php中,进程通信的方法有FIFO,SystemV消息队列,SystemV共享内存,SystemV信号量,这些SystemV相关的方法默认是不启用的,如果需要的话,你需要打开--enable-sysvsem--enable--sysvshm--enable-sysvmsg管道和SystemV消息队列和SystemV信号量是编译和安装时在内核级别共享信息的方式。两个或多个进程共享驻留在内核中的某些信息。每个访问共享信息的操作都涉及对内核的系统调用。消息队列中每条消息关联的类型字段提供了两个特征类型字段,可以用来标识消息,允许多个进程在单个队列上多路复用(multiplex)消息。例如,Type字段的一个值标识从各个客户端到服务器的消息,而每个客户端唯一的另一个值标识从服务器到各个客户端的消息。每个客户端的进程ID自然可以用作每个客户端唯一的类型字段。类型字段可以用作优先级字段。这允许接收者以先进先出FIFO以外的某种顺序读出单个消息。这不同于管道或FIFO。使用管道时,必须按照写入的顺序读取数据。当使用SystemV消息队列时,消息可以以任何顺序读出,只要它匹配与消息类型关联的值。并且我们可以指定MSG_IPC_NOWAIT标志来调用msg_receive从队列中读取任何给定类型的消息,但是如果没有给定类型的消息,它会立即返回。本文主要记录PHP使用消息队列进行通信的方法和经验。//生成一个消息队列键//生成一个消息队列键$msgKey=ftok(__FILE__,'w');/**msg_get_queue()返回一个id,可以用SystemV访问SystemV消息队列具有给定{key}的消息队列。第一次调用使用可选的{perms}创建消息队列。为相同的{key}第二次调用msg_get_queue()将返回不同的消息队列标识符,但两个标识符都访问相同的底层消息队列。*///生成消息队列$msgQueue=msg_get_queue($msgKey,0666);//检查队列是否存在$status=msg_queue_exists($msgKey);var_dump($status);//查看当前消息的一些细节/***msg_perm.uid队列所有者的uid。*msg_perm.gid队列所有者的gid。*msg_perm.mode队列的文件访问模式。*msg_stime最后一条消息发送到队列的时间。*msg_rtime从队列中接收到最后一条消息的时间。*msg_ctime队列最后一次改变的时间。*msg_qnum等待读取的消息数e队列。*msg_qbytes一个消息队列中允许的最大字节数。在Linux上,可以通过/proc/sys/kernel/msgmnb读取和修改此值。*msg_lspid将最后一条消息发送到队列的进程的pid。*msg_lrpid从队列中接收到最后一条消息的进程的pid。**/$msgStat=msg_stat_queue($msgQueue);print_r($msgStat);//向消息队列添加数据,默认数据会被序列化msg_send($msgQueue,1,'hahha,1');msg_send($msgQueue,2,'oooooo,2');msg_send($msgQueue,1,'xxxxx,3');//从消息队列中读取一条消息msg_receive($msgQueue,1,$message_type,1024,$message1);msg_receive($msgQueue,1,$message_type,1024,$message2);//msg_receive($msgQueue,1,$message_type,1024,$message3,true,MSG_IPC_NOWAIT);msg_receive($msgQueue,2,$message_type,1024,$message3);$msgStat=msg_stat_queue($msgQueue);print_r($msgStat);msg_remove_queue($msgQueue);echo$message1.PHP_EOL;echo$message2.PHP_EOL;echo$message3.PHP_EOL;结果如下:Array([msg_perm.uid]=>0[msg_perm.gid]=>0[msg_perm.mode]=>438[msg_stime]=>0[msg_rtime]=>0[msg_ctime]=>1492759388[msg_qnum]=>0[msg_qbytes]=>16384[msg_lspid]=>0[msg_lrpid]=>0)Array([msg_perm.uid]=>0[msg_perm.gid]=>0[msg_perm.mode]=>438[msg_stime]=>1492759388[msg_rtime]=>1492759388[msg_ctime]=>1492759388[msg_qnum]=>0[msg_qbytes]=>16384[msg_lspid]=>23336[msg_lrpid]=>23336)hahha,1xxxxx,3ooooo,2手册中msg_send和msg_receive的定义如下boolmsg_send(resource$queue,int$msgtype,mixed$message[,bool$serialize=true[,bool$blocking=true[,int&$errorcode]]])msg_send()发送类型为msgtype的消息(必须大于0)到queue指定的消息队列。boolmsg_receive(资源$queue,int$desiredmsgtype,int&$msgtype,int$maxsize,mixed&$message[,bool$unserialize=true[,int$flags=0[,int&$errorcode]]])msg_receive()将从指定队列接收第一条消息,其类型由desiredmsgtype指定。msg_receive的第二个参数desiredmsgtype指定了从队列中获取什么样的消息。如果desiredmsgtype等于0,则返回队列中的第一条消息。每个消息队列维护为一个先进先出的链表,所以类型为0,返回队列中最早的消息。(但在这种情况下,会出现阻塞,$flags应设置为MSG_IPC_NOWAIT)如果desiredmsgtype大于0,则返回type值为desiredmsgtype的第一条消息。如果desiredmsgtype小于0,则返回type值小于或等于desiredmsgtype参数绝对值的消息中类型最小的第一条消息。(但在这种情况下,会出现阻塞,$flags要设置为MSG_IPC_NOWAIT)如果你要读取的消息类型不存在,程序就会阻塞,直到有相应类型的消息写入队列。当然可以通过设置$flags=MSG_IPC_NOWAIT来设置为非阻塞。然后是进程间通信。代码如下://获取消息队列键$key=ftok(__FILE__,'w');//创建消息队列$queue=msg_get_queue($key);$孩子=[];$数=5;$result=[];for($i=0;$i<$num;$i++){$pid=pcntl_fork();if($pid==-1){die('分叉失败');}elseif($pid>0){$child[]=$pid;}elseif($pid==0){$sleep=rand(1,4);msg_send($queue,2,array('name'=>$i.'~'.$sleep));睡眠($睡眠);退出(0);}}while(count($child)){foreach($childas$k=>$pid){$res=pcntl_waitpid($pid,$status,WNOHANG);如果($res==-1||$res>0){unset($child[$k]);msg_receive($queue,2,$message_type,1024,$data);$结果[]=$数据;}}}msg_remove_queue($queue);print_r($result);结果如下:Array([0]=>Array([name]=>1~3)[1]=>Array([name]=>0~3)[2]=>数组([名称]=>3~2)[3]=>数组([名称]=>4~4)[4]=>数组([名称]=>2~4))