php進程通訊--System V 消息隊列

在php中,進程通訊的方法有FIFO,System V消息隊列,SystemV共享內存,System V信號量
這些System V的相關方法默認是不開啓的,若是須要,則要再編譯安裝的時候打開
--enable-sysvsem --enable --sysvshm --enable-sysvmsg
管道和System V消息隊列以及System V信號量是內核級的共享信息的方式。兩個或多個進程共享駐留在內核中的某些信息。訪問共享信息的每次操做涉及對內核的一次系統調用。
消息隊列中的每一個消息相關聯的類型字段提供了兩個特性php

  • 類型字段能夠用於標識消息,從而容許多個進程在單個隊列上覆用(multiplex)消息。 例如,類型字段的某個值用於標識從各個客戶到服務器的消息,對於每個客戶均爲惟一的另外某個值用於標識從服務器到各個客戶的消息。每一個客戶的進程ID天然能夠用做對於每一個客戶均爲惟一的類型字段。服務器

  • 類型字段能夠用做優先級字段。這容許接受者以不一樣於先進先出FIFO的某個順序讀出各個消息。這點不一樣於管道或FIFO,使用管道時,數據必須是以寫入的順序讀出。使用System V消息隊列時,消息可以以任意順序讀出,之喲啊跟消息類型關聯的值一致就行。並且咱們能夠指定MSG_IPC_NOWAIT標誌調用msg_receive從某個隊列中讀出某個給定類型的任意消息,可是沒有給定類型的消息存在,那就當即返回。ide

本文主要記錄一下php利用消息隊列進行通訊的方法和心得。ui

// 生成一個消息隊列的key

// 生成一個消息隊列的key
$msgKey = ftok(__FILE__,'w');

/**
    msg_get_queue() returns an id that can be used to access the System V message
    queue with the given {key}. The first call creates the message queue with the
    optional {perms}. A second call to msg_get_queue() for the same {key} will
    return a different message queue identifier, but both identifiers access the
    same underlying message queue.
 */
// 產生一個消息隊列
$msgQueue = msg_get_queue($msgKey,0666);

// 檢查一個隊列是否存在
$status = msg_queue_exists($msgKey);
var_dump($status);

// 查看當前消息的一些詳細信息
/**
 * msg_perm.uid The uid of the owner of the queue.
 * msg_perm.gid The gid of the owner of the queue.
 * msg_perm.mode The file access mode of the queue.
 * msg_stime The time that the last message was sent to the queue.
 * msg_rtime The time that the last message was received from the queue.
 * msg_ctime The time that the queue was last changed.
 * msg_qnum The number of messages waiting to be read from the queue.
 * msg_qbytes The maximum number of bytes allowed in one message queue. On Linux, this value may be read and modified via /proc/sys/kernel/msgmnb.
 * msg_lspid The pid of the process that sent the last message to the queue.
 * msg_lrpid The pid of the process that received the last message from the queue.
 *
 */
$msgStat = msg_stat_queue($msgQueue);
print_r($msgStat);

// 把數據加入消息隊列,默認數據會被序列化
msg_send($msgQueue,1,'hahha,1');
msg_send($msgQueue,2,'ooooo,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;

結果以下:this

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,1
xxxxx,3
ooooo,2

手冊中對msg_send和msg_receive這兩個定義以下。code

bool msg_send ( resource $queue , int $msgtype , mixed $message [, bool $serialize = true [, bool $blocking = true [, int &$errorcode ]]] )
msg_send() sends a message of type msgtype (which MUST be greater than 0) to the message queue specified by queue. 

bool msg_receive ( resource $queue , int $desiredmsgtype , int &$msgtype , int $maxsize , mixed &$message [, bool $unserialize = true [, int $flags = 0 [, int &$errorcode ]]] )
msg_receive() will receive the first message from the specified queue of the type specified by desiredmsgtype.

msg_receive的第二個參數desiredmsgtype ,指定從隊列中獲取什麼樣的消息。隊列

  • 若是desiredmsgtype等於0,那麼就返回改隊列中的第一個消息。每個消息隊列都是做爲一個先進先出的鏈表維護,所以type爲0,返回該隊列中最先的消息。(可是這個狀況下,會出現阻塞,$flags要設置爲MSG_IPC_NOWAIT)進程

  • 若是desiredmsgtype 大於0,那就返回其類型值爲desiredmsgtype的第一個消息。ip

  • 若是desiredmsgtype 小於0,那就返回其類型值小於或等於desiredmsgtype參數的絕對值的消息中類型最小的第一個消息。(可是這個狀況下,會出現阻塞,$flags要設置爲MSG_IPC_NOWAIT)內存

  • 若是你要讀取的那類消息不存在,程序就會阻塞,直到有對應類型的消息寫入到隊列裏。固然,能夠經過設置$flags = MSG_IPC_NOWAIT來設置爲非阻塞。

而後就是多進程間通訊了。代碼以下:

// 獲取消息隊列key
$key = ftok(__FILE__,'w');

// 建立一個消息隊列
$queue = msg_get_queue($key);

$child = [];
$num   = 5;
$result = [];

for($i=0;$i<$num;$i++){
    $pid = pcntl_fork();
    if($pid == -1) {
        die('fork failed');
    } else if ($pid > 0) {
        $child[] = $pid;
    } else if ($pid == 0) {
        $sleep = rand(1,4);
        msg_send($queue,2,array('name' => $i.'~'.$sleep));
        sleep($sleep);
        exit(0);
    }
}

while(count($child)){
    foreach($child as $k => $pid) {
        $res = pcntl_waitpid($pid,$status,WNOHANG);
        if ($res == -1 || $res > 0 ) {
            unset($child[$k]);
            msg_receive($queue,2,$message_type,1024,$data);
            $result[] = $data;
        }
    }
}
msg_remove_queue($queue);
print_r($result);

結果以下:

Array
(
    [0] => Array
        (
            [name] => 1~3
        )

    [1] => Array
        (
            [name] => 0~3
        )

    [2] => Array
        (
            [name] => 3~2
        )

    [3] => Array
        (
            [name] => 4~4
        )

    [4] => Array
        (
            [name] => 2~4
        )

)
相關文章
相關標籤/搜索