It looks like msg_receive() allocates a memory with size $maxsize, and only then tries to receive a message from queue into allocated memory. Because my script dies with $maxsize = 1 Gib, but works with $maxsize = 10 Kib.
(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)
msg_receive — Получение сообщения из очереди сообщений
$queue
,$desired_message_type
,&$received_message_type
,$max_message_size
,&$message
,$unserialize
= true
,$flags
= 0,&$error_code
= null
msg_receive() получает первое сообщение из задаваемой параметром
queue
очереди сообщений с типом, указанным в desired_message_type
.
queue
Очередь сообщений.
desired_message_type
Если в desired_message_type
указано 0, возвращается первое
сообщение из очереди. Если desired_message_type
больше 0, то
возвращается первое сообщение с указанным типом. Если desired_message_type
меньше 0, то возвращается первое сообщение с типом, меньшим или равным по модулю
указанному в desired_message_type
. Если нет сообщений,
соответствующих критериям, ваш скрипт ожидает их появления в очереди.
Вы можете изменить это поведение, указав MSG_IPC_NOWAIT
в
параметре flags
.
received_message_type
В этом параметре сохраняется тип полученного сообщения.
max_message_size
Максимальный размер принимаемого сообщения задаётся в max_message_size
;
если сообщение в очереди больше этого размера, то функция завершается ошибкой
(если вы не установите flags
как описано ниже).
message
Полученное сообщение сохраняется в message
,
если не было ошибок при получении.
unserialize
Если установлено в true
, сообщение рассматривается как сериализованое с
использованием того же механизма, что и в модуле сессий. Сообщение десериализуется,
а затем возвращается в ваш скрипт. Это позволяет вам легко получать массивы и
сложные объекты из других PHP-скриптов, или, если вы используете WDDX-сериализатор,
из любых совместимых с WDDX источников.
Если в unserialize
указано false
,
сообщение возвращается в виде бинарно-безопасной строки.
flags
Необязательный параметр flags
позволяет вам передать
флажки в низкоуровневый системный вызов msgrcv. По умолчанию его значение 0,
однако вы можете указать одно или несколько следующих значений (складывая их или
выполняя операцию бинарного ИЛИ).
MSG_IPC_NOWAIT |
Если нет сообщений, удовлетворяющих условиям desired_message_type ,
возвращаться немедленно, а не ждать. Функция завершается ошибкой и возвращает
целочисленное значение MSG_ENOMSG .
|
MSG_EXCEPT |
Использование этого флага в комбинации с указанным в
desired_message_type положительным значением,
позволяет получить первое сообщение, тип которого не равен значению
desired_message_type . |
MSG_NOERROR |
Если размер сообщения превышает max_message_size ,
то установка этого флага приводит к усечению сообщения до max_message_size
без сигнализирования об ошибке.
|
error_code
Если функция завершается аварийно, необязательный параметр error_code
будет содержать значение системной переменной errno.
Возвращает true
в случае успешного выполнения или false
в случае возникновения ошибки.
При успешном завершении, структура данных очереди сообщений обновляется следующим образом:
msg_lrpid
содержит идентификатор вызвавшего процесса,
msg_qnum
уменьшается на 1 и
msg_rtime
устанавливается соответственно текущему времени.
Версия | Описание |
---|---|
8.0.0 |
Параметр queue теперь ожидает экземпляр SysvMessageQueue;
ранее ожидался ресурс (resource).
|
It looks like msg_receive() allocates a memory with size $maxsize, and only then tries to receive a message from queue into allocated memory. Because my script dies with $maxsize = 1 Gib, but works with $maxsize = 10 Kib.
This is meant to be run as your apache user in a terminal, call script in note of msg_send and they will communicate.
#! /usr/bin/env php
<?php
$MSGKEY = 519051; // Message
$msg_id = msg_get_queue ($MSGKEY, 0600);
while (1) {
if (msg_receive ($msg_id, 1, $msg_type, 16384, $msg, true, 0, $msg_error)) {
if ($msg == 'Quit') break;
echo "$msg\n";
} else {
echo "Received $msg_error fetching message\n";
break;
}
}
msg_remove_queue ($msg_id);
?>
It seems that a maxsize of 2Mb is some sort of a threshold for php, above that msg_receive() starts to use a lot of CPU (with a sender that is pushing messages non-stop receiving 10000 messages jumps up from 0.01 sec to 1.5 sec on my computer) so try to stay below that thresholod if you can.
<?php error_reporting(E_ALL);
/**
* Example for sending and receiving Messages via the System V Message Queue
*
* To try this script run it synchron/asynchron twice times. One time with ?typ=send and one time with ?typ=receive
*
* @author Thomas Eimers - Mehrkanal GmbH
*
* This document is distributed in the hope that it will be useful, but without any warranty;
* without even the implied warranty of merchantability or fitness for a particular purpose.
*/
header('Content-Type: text/plain; charset=ISO-8859-1');
echo "Start...\n";
// Create System V Message Queue. Integer value is the number of the Queue
$queue = msg_get_queue(100379);
// Sendoptions
$message='nachricht'; // Transfering Data
$serialize_needed=false; // Must the transfer data be serialized ?
$block_send=false; // Block if Message could not be send (Queue full...) (true/false)
$msgtype_send=1; // Any Integer above 0. It signeds every Message. So you could handle multible message
// type in one Queue.
// Receiveoptions
$msgtype_receive=1; // Whiche type of Message we want to receive ? (Here, the type is the same as the type we send,
// but if you set this to 0 you receive the next Message in the Queue with any type.
$maxsize=100; // How long is the maximal data you like to receive.
$option_receive=MSG_IPC_NOWAIT; // If there are no messages of the wanted type in the Queue continue without wating.
// If is set to NULL wait for a Message.
// Send or receive 20 Messages
for ($i=0;$i<20;$i++) {
sleep(1);
// This one sends
if ($_GET['typ']=='send') {
if(msg_send($queue,$msgtype_send, $message,$serialize_needed, $block_send,$err)===true) {
echo "Message sendet.\n";
} else {
var_dump($err);
}
// This one received
} else {
$queue_status=msg_stat_queue($queue);
echo 'Messages in the queue: '.$queue_status['msg_qnum']."\n";
// WARNUNG: nur weil vor einer Zeile Code noch Nachrichten in der Queue waren, muss das jetzt nciht mehr der Fall sein!
if ($queue_status['msg_qnum']>0) {
if (msg_receive($queue,$msgtype_receive ,$msgtype_erhalten,$maxsize,$daten,$serialize_needed, $option_receive, $err)===true) {
echo "Received data".$daten."\n";
} else {
var_dump($err);
}
}
}
}
?>
Consider this e.g. Linux situation:
<?php
//file send.php
$ip = msg_get_queue(12340);
msg_send($ip,8,"abcd",false,false,$err);
//-----------------------------------------------------
<?php
//file receive.php
$ip = msg_get_queue(12340);
msg_receive($ip,0,$msgtype,4,$data,false,null,$err);
echo "msgtype {$msgtype} data {$data}\n";
msg_receive($ip,0,$msgtype,4,$data,false,null,$err);
echo "msgtype {$msgtype} data {$data}\n";
?>
Now run:
in terminal #1 php5 receive.php
in terminal #2 php5 receive.php
in terminal #3 php5 send.php
Showing messages from queue will flip-flop. It means you run once send.php, the message will be shown in terminal #1. Second run it will be in t#2, third #1 and so on.