专栏首页仙士可博客php进程通信-消息队列

php进程通信-消息队列

php多进程通信,有各种各样的方法(进程信号,消息队列,管道,共享内存,socket等等)

本文主要讲php利用linux 消息队列的通信方法

注意:多进程系列文章,都建立在linux环境,php-cli运行模式下

一:消息队列通信介绍

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。

消息队列的最佳定义是:内核地址空间中的内部链表。消息可以顺序地发送到队列中,并以几种不同的方式从队列中获取。当然,每个消息队列都是由 IPC标识符所唯一标识的。

二:php消息队列扩展

php如果要使用linux的消息队列,需要安装sysvmsg扩展,官方文档地址:http://php.net/manual/zh/book.sem.php

三:php使用消息队列

1:获取一个IPC标识符ftok();

ftok,可将项目路径与文件标识转换成一个IPC标识符,该标识符可用于创建消息队列

2:获取/创建一个消息队列msg_get_queue()

使用linux命令ipcs -q 可查看系统当前的消息队列数

3:插入数据到队列msg_send()

msg_send (

 resource $queue(消息队列资源句柄) , 

int $msgtype(插入数据的类型,用来标识该队列自己的消息类型,自己自定义,必须大于0) , 

mixed $message(插入的数据,可以为数组,下一个参数可以序列化数据)

 [, bool $serialize = TRUE(是否序列化数据,默认是)

 [, bool $blocking = TRUE (如果消息太大而无法放入队列(linux消息队列限制),则脚本将等待另一个进程从队列中读取消息,并释放足够的空间以发送消息。这被称为阻塞; 您可以通过设置可选blocking参数来防止阻塞FALSE,在这种情况下,如果消息对于队列来说太大,msg_send()将立即返回,并将可选参数FALSE设置 errorcode为MSG_EAGAIN,表示您应稍后尝试再次发送消息。)

[, int &$errorcode ]]] (错误标识));

插入成功之后,ipcs可看到message多了一条:

4:取出一条数据msg_receive

msg_receive ( 

resource $queue , (消息队列资源句柄)

int $desiredmsgtype (要取出的消息队列类型,如果为0,则不筛选类型,直接返回最先插入的那条,大于0,则筛选类型,返回最先插入的类型数据,小于0,则返回小于等于绝对值的数据,如果消息队列暂无满足要求的数据,则阻塞或者返回false,由flag参数配置), 

int &$msgtype (当取出数据时,该变量会赋值为该数据的类型),

 int $maxsize (消息的最大大小被指定的被接受 maxsize; 如果队列中的消息大于此大小,则该功能将失败(除非flags按照以下说明设置 )该参数较迷,没有理解), 

mixed &$message (当取出数据时,该变量会赋值为该数据)

[, bool $unserialize = TRUE(是否反序列化数据)

 [, int $flags = 0 

该选项flags允许您将标志传递给低级msgrcv系统调用。它默认为0,但您可以指定一个或多个以下值(通过将它们相加或相加)。

MSG_IPC_NOWAIT

如果没有消息 desiredmsgtype,立即返回,不要等待。该函数将失败并返回对应的整数值MSG_ENOMSG。

MSG_EXCEPT

将此标志与desiredmsgtype大于0 结合使用 会导致函数接收到不等于的第一条消息 desiredmsgtype。

MSG_NOERROR

如果消息长于maxsize,则设置此标志将截断消息, maxsize并且不会发出错误信号。

[, int &$errorcode ]]] )如果该函数失败,errorcode 则可选项将被设置为系统errno变量的值。

5:删除队列msg_remove_queue ( resource $queue )

顾名思义,该函数可删除一个消息队列

四:linux相关操作

在linux中,主要用ipcs(查看) ipcrm(删除)

1:ipcs  

ipcs -h,可查看帮助

主要需要记住的是:

ipcs -q (查看消息队列)

ipcs -l  (查看系统配置)

2:ipcrm

ipcrm -h:

ipcrm,只要能删除就行啦~~

ipcrm -q id  (删除指定消息队列)

3:注意!

在使用消息队列时,请注意消息队列的默认限制(限制消息队列数,和消息队列大小),

当到达上限时,会使得写入消息队列操作阻塞(默认阻塞)

五:封装类

创建队列方法,好像有点问题(创建后无法正确使用队列,估计是__FILE__常量问题),暂时没查

使用封装类方法:

$message_queue_key= ftok(__FILE__, 'a');
if(msg_queue_exists($message_queue_key)){//如果有该消息队列,则删除,用于清空之前队列的无用数据
    msg_remove_queue(msg_get_queue($message_queue_key, 0666));
}
$message_queue= msg_get_queue($message_queue_key, 0666);
$msg_queue = new MsgQueue($message_queue);
<?php

/**
 * Created by PhpStorm.
 * User: tioncico
 * Date: 18-5-29
 * Time: 下午11:00
 */
class MsgQueue
{

    public $queue;

    public function __construct($queue)
    {
        $this->queue = $queue;
    }

    public function push($data, $type = 1)
    {
        $result = msg_send($this->queue, $type, $data);
        return $result;
    }

    public function pop($type = 0,$flags = MSG_IPC_NOWAIT)
    {
        msg_receive($this->queue, $type, $message_type, 1024, $message,true,$flags);
//        var_dump($message_type);
//        msg_receive($this->queue,$type,$message_type,1024,$message);
        return $message;
    }

    public function close()
    {
        return msg_remove_queue($this->queue);
    }

    /**
     * 创建一个队列(TODO:疑问待解决)
     * @param string $path_name
     * @param string $prop
     * @param string $perms
     * @return array
     */
    public static function getQueue($path_name = __FILE__, $prop = '1', $perms = '0666')
    {
        $data              = array();
        $data['queue_key'] = ftok($path_name, $prop);
        $data['queue']     = msg_get_queue($data['queue_key'], $perms);
        return $data;
    }
}

七:使用例子

<?php
include_once 'new/MsgQueue.php';
$message_queue_key= ftok(__FILE__, 'a');
$message_queue= msg_get_queue($message_queue_key, 0666);
$queue_obj = new MsgQueue($message_queue);
$pid = pcntl_fork();
if($pid>0){//主进程入列
    while(1){
        $msg = $queue_obj->push((array('a'=>321312,'v'=>'casd')),12456);
        sleep(2);
    }
}else{//子进程出列
    while(1){
        $message = $queue_obj->pop();
        var_dump($message);
        sleep(1);
    }
}

输出:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • php设计模式-注册器模式

    设计模式参考地址:http://larabase.com/collection/5/post/143

    仙士可
  • redis 通信协议,php实现redis协议

    string(34) "*3CRLF$3CRLFsetCRLF$1CRLFa$8CRLFtioncicoCRLF"

    仙士可
  • tp框架实现数组翻页

    自己在尝试做一个wap文字游戏,有一些数据内容是序列化后的数据,取出来是数组,所以做了一个tp数组翻页函数

    仙士可
  • liteos队列

    队列又称消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间。任务能够从队列里...

    233333
  • Qemu-KVM 网络性能优化实践

    在做优化之前,腾讯云上使用的母机单队列,性能只有14w pps,已有的多队列版本,在20w+ pps左右,不是很理想......

    serena
  • Java数据结构和算法(五)——队列

      前面一篇博客我们讲解了并不像数组一样完全作为存储数据功能,而是作为构思算法的辅助工具的数据结构——栈,本篇博客我们介绍另外一个这样的工具——队列。栈是后进先...

    IT可乐
  • 「 从0到1学习微服务SpringCloud 」11 补充篇 RabbitMq实现延迟消费和延迟重试

    延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费。

    KEN DO EVERTHING
  • 三分钟基础:什么是队列?

    像线程池、异步队列、消息队列等有限的资源容器中,往往存储大量的任务事件,这些大量的任务事件需要进行有条理的进行任务分发以及各种情况处理,为了能够使得资源容器的正...

    帅地
  • Java队列学习第一篇之列介绍

    队列大家都知道,但是在Java中队列分哪几种呢?清楚吗?都有哪些地方用到了队列呢?最常用的场景的就是消息中间件,比如各种MQ都是使用的队列来的。如果没有用过消息...

    凯哥Java
  • 算法与数据结构(二) 栈与队列的线性和链式表示(Swift版)

    数据结构中的栈与队列还是经常使用的,栈与队列其实就是线性表的一种应用。因为线性队列分为顺序存储和链式存储,所以栈可以分为链栈和顺序栈,队列也可分为顺序队列和链队...

    lizelu

扫码关注云+社区

领取腾讯云代金券