"Multi-tasken" met een PHP/inetd socketserver
Een socket applicatie kun je schrijven in combinatie met inetd of xinetd. Je kunt de data via STDIN binnen php gebruiken. Maar wat als je ook nog elke 10 seconden iets uit wilt voeren? In dit artikel beschrijf ik hoe je dit in combinatie met inetd kunt realiseren.
Met inetd kun je op zeer gemakkelijke wijzen een socket applicatie schrijven. Ik zal kort uitleggen hoe je dat op kunt zetten.
Systeemconfiguratie
Voeg dit toe in /etc/services:
scriptorama 30000/tcp #Scriptorama test socket
Hiermee definieer je een service genaamd scriptorama, luiterend op tcp poort 30000. Zorg er uiteraard voor dat je een vrije poort gebruikt.
Vervolgens moet je in /etc/inetd.conf het volgende toevoegen:
scriptorama stream tcp nowait root /path/to/socket.php socket.php
Om dit actief te maken moet inetd herstart worden.
Eerst even kijken welk process het is, en vervolgens kill -HUP:
# ps ax|grep inet
96 ?? Ss 0:01.61 /usr/sbin/inetd -wW
# kill -HUP 96
We hebben nu een draaiende configuratie die de data via poort 30000 naar ons php script sluist. Deze data kan via de standaard input (STDIN) worden gelezen.
Script
-
#!/usr/local/bin/php -q
-
<?php
-
-
$line = '';
-
-
//loop infinitely
-
while(1) {
-
-
//read stdin
-
-
//if stdin is not empty, concat it to the line
-
if($stdin != '') {
-
$line .= $stdin;
-
}
-
-
//if we encounter a newline parse it to datahandler and clear line
-
$line = '';
-
}
-
-
//timer: execute ever second
-
if($time> $prevtime) {
-
-
//execute our stuff every 10 seconds
-
if($delayTimer> 9) {
-
echo "10 seconden voorbij";
-
$delayTimer = 0;
-
}
-
$delayTimer++;
-
$prevtime = $time;
-
}
-
-
//sleep 50 microseconds to save cpu power
-
}
-
-
?>
Zorg er voor dat dit script executable is door het volgende commando uit te voeren:
# chmod a+x socket.php
Zie ook dit scriptorama artikel voor meer informatie over commandline opties.
Beschrijving script
Als eerste wordt er een filepointer naar de stream php://stdin geopend. Wat vervolgens opvalt is de stream_set_blocking functie. Normaal gesproken wacht de fgets functie op een newline. Het script stopt dus als het ware totdat er data via de socket is ingevoerd. Door stream_set_blocking uit te schakelen wordt er niet gewacht op input van de client maar gaat het script gelijk verder. Met een oneindige while loop wordt de data via STDIN ingelezen en aan de string $line toegevoed. Zodra er een newline wordt gedetecteerd wordt de gecollecteerde input naar de client ge-echo'ed en $line weer leeg gemaakt.
Ook is er een timer aanwezig die elke 10 seconden de string "10 seconden voorbij" naar de client echo'ed. De usleep functie zorgt er voor dat de cpu niet 100% belast wordt door 50 milliseconde te wachten.
Ik heb ook naar het concept "ticks" binnen PHP gekeken waarbij sommigen claimen een soort multi-tasking te kunnen bewerkstelligen. Ik heb het getest, maar dat blijkt toch niet zo te zijn. De gedeclareerde functies worden wel gelijktijdig gestart, maar blijken toch op elkaar te wachten. Dit is jammer omdat je af en toe wel echte multitasking kunt gebruiken.
Lees hier meer over de stream_set_blocking functie.
Volg Scriptorama via RSS!
Reageer ook!
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>