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 — Liest eine Nachricht aus einer Nachrichten-Warteschlange aus
$queue
,$desired_message_type
,&$received_message_type
,$max_message_size
,&$message
,$unserialize
= true
,$flags
= 0,&$error_code
= null
msg_receive() liest die erste Nachricht vom Typ
desired_message_type
aus der durch
queue
angegeben Warteschlange aus.
queue
Die Nachrichten-Warteschlange.
desired_message_type
Wenn desired_message_type
gleich 0 ist, wird die
erste Nachricht aus der Warteschlange zurückgegeben. Wenn
desired_message_type
größer als 0 ist, wird die
erste Nachricht genau diesen Typs zurückgegeben. Wenn
desired_message_type
kleiner als 0 ist, wird die
erste Nachricht kleiner oder gleich dem absoluten Wert von
desired_message_type
zurückgegeben. Wenn keine
passende Nachricht existiert, blockiert diese Funktion solange, bis
eine passende Nachricht verfügbar ist. Durch das Setzen des Flags
MSG_IPC_NOWAIT
im Parameter
flags
kann das blockierende Verhalten verhindert
werden.
received_message_type
In diesem Parameter wird der Typ der empfangenen Nachricht gespeichert.
max_message_size
Die maximale Größe der zu akzeptierenden Nachricht wird durch
max_message_size
angegeben; Wenn die Nachricht
in der Nachrichten-Warteschlange größer ist, als dieser Wert, schlägt
die Funktion fehl (es sei denn, es wird das entsprechende Flag im
Parameter flags
gesetzt).
message
Die empfangene Nachricht wird in message
gespeichert, es sei denn es tritt ein Fehler beim Empfang auf.
unserialize
Wenn dieser Wert auf true
gesetzt wird, wird die Nachricht behandelt,
als wäre sie mit demselben Mechanismus serialisiert worden, wie das
Session-Modul. Die Nachricht wird deserialisiert und zurückgegeben.
Dies erlaubt einen einfachen Empfang von Arrays und komplexen
Objektstrukturen von anderen PHP-Skripten. Wenn Sie den WDDX-Serializer
verwenden, erlaubt es den Empfang von einer WDDX-kompatiblen Quelle.
Wenn unserialize
false
ist, wird die Nachricht
als binärsicherer String zurückgegeben.
flags
Der optionale Parameter flags
erlaubt die
Weitergabe von Flags an den low-level msgrcv-Systemaufruf. Der
Standardwert liegt bei 0, aber es können einer oder mehrere der
folgenden Werte übergeben werden (AND- oder OR-verknüpft).
MSG_IPC_NOWAIT |
Wenn kein Wert des übergebenen Typs
desired_message_type in der Warteschlange
vorhanden ist, gibt die Funktion sofort zurück, statt zu warten.
Die Funktion schlägt fehl und gibt den Integerwert entsprechend an
MSG_ENOMSG zurück.
|
MSG_EXCEPT |
Dieses Flag sorgt in Kombination mit einem
desired_message_type größer als 0 dafür,
dass die Funktion die erste Nachricht zurück gbit, die nicht
gleich desired_message_type ist.
|
MSG_NOERROR |
Wenn die Nachricht länger als
max_message_size ist, wird durch Setzen
diese Flags die Nachricht auf
max_message_size gekürzt, und die Funktion
signalisiert keinen Fehler.
|
error_code
Wenn die Funktion fehlschlägt, wird der optionale
error_code
auf den Wert der
System-errno-Variable gesetzt.
Gibt bei Erfolg true
zurück. Bei einem Fehler wird false
zurückgegeben.
Bei erfolgreicher Ausführung wird die Datenstruktur der
Nachrichten-Warteschlange folgendermaßen aktualisiert:
msg_lrpid
wird auf die Prozess-ID des aufrufenden
Prozesses gesetzt, msg_qnum
wird um 1 dekrementiert, und
msg_rtime
wird auf die aktuelle Zeit gesetzt.
Version | Beschreibung |
---|---|
8.0.0 |
queue erwartet nun eine
SysvMessageQueue-Instanz; vorher wurde eine
resource erwartet.
|
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 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);
}
}
}
}
?>
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.
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.
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);
?>