PHP memory leak in client socket (UDP) - php

:)
I am trying to receive data from a c# realtime application in my php server and then move a picture in the browser according to the data.
There is no problem in data send and receive, but the memory usage for chrome is getteng more and more when running the code.
If I close the socket inside the while loop, performance gets very low but mem usage gets normal.So this is about the open socket...
here is the php code :
<?php
//http://www.binarytides.com/udp-socket-programming-in-php/
//Create a UDP socket
if(!($sock = socket_create(AF_INET, SOCK_DGRAM, 0)))
{
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
echo "Socket created \n";
// Bind the source address
if( !socket_bind($sock, "0.0.0.0" , 41181) )
{
die("Could not bind socket : [$errorcode] $errormsg \n");
}
echo "Socket bind OK \n";
//Do some communication, this loop can handle multiple clients
while(1)
{
//echo "Waiting for data ... \n";
$r = socket_recvfrom($sock, $buf, 20, 0, $remote_ip, $remote_port);
?>
<script type="text/javascript">
var data = "<?php echo $buf ?>";
</script>
<?php
}
socket_close($sock);
?>
and here is the c# function (data sender):
public static void SendUDP(string hostNameOrAddress, int destinationPort, string data, int count)
{
//class member : Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp);
//socket is defined as class member and used here
for (int i = 0; i < count; i++)
{
socket.SendTo(buffer, endPoint);
}
}
Thanks ! :)

The technique you're using is called "long polling". It's a funny way to emulate bidirectional communication, especially with old browsers, but has its downsides.
The problem is that, with time, you are sending a huge amount of payload to the browser.
As you're continuously writing to the browser, the page size increases, and, with it, the DOM tree. All of this has to be stored in memory. I'd assume that when you send only a few of the script chunks, the performance is still ok. But thousands and ten thousands of them will of course eat up your memory.
Also, if you're using diagnostic tools, such as the Chrome Developer Tools or Firebug in Firefox, they store a lot of debugging information, which also consume a lot of memory. (Try disabling them.)
If you've written this code just for fun and experimenting, you shouldn't worry about the memory consumption; it's inherent to long polling.
But if you're trying to write a web application with a real bi-directional communication, you should use something like Web Sockets (and maybe a different language than PHP on the server side).

This is not a real answer to my question, but my experience may help someone.
I couldn't do this "long polling" with a PHP server, and it was the fault of PHP, not the browser.
I have developed a good application working this way using a Node.js server.
My C# app is used to process images from a camera. The real-time data resulting the image processing is sent over to the Node.js server and from the server to the browser .
Now I use the web technologies to develop a graphical user interface that was very hard to achieve in .Net, and it has many other benefits...

Related

PHP socket server takes a lot of CPU usage

I follow some tutorial (1), (2) on internet to create a PHP socket server, and it works quite well. There is only thing is my PHP script takes a lot of CPU usage (99%).
I do not show code here, because my code is similar to the above tutorials.
The main action is written in an infinitive loop
while (true)
{
$this->selectChangedSockets();
$this->handleNewClients();
$this->receiveInput();
$this->checkDisconnections();
}
The functions inside the my loop are just to handle inputs (new client's connection, client's message, etc.), and handle outputs (send back to the client's message, etc.)
My php script is always on top in CPU usage (99%). I read this, and they suggest to put "sleep(1)" in the loop. My socket server is for the real time applications, and I am not sure this is a good way to go?
Anyone who has experience with php socket can give me any suggestion?
Is there any standard php socket server library?
or do I need to run the script in the background?
Updated
Because you mention the function socket_select may pause a little bit, I give you my code:
private function selectChangedSockets()
{
// Reset array of changed sockets
$this->changed = array_merge(array($this->socket), $this->clients);
$null = null;
$res = socket_select($this->changed, $null, $null, 0);
if (false === $res)
{
echo "socket_select() failed, reason: " .
socket_strerror(socket_last_error()) . "\n";
}
}
public function run()
{
while (true) {
$this->selectChangedSockets();
//$this->handleNewClients();
//$this->receiveInput();
//$this->checkDisconnections();
}
}
My PHP script still takes 99% CPU usage.
Your selectChangedSockets method should be blocking, meaning, not return until there are changes on the sockets. See socket_select.
A while ( true ) {} will use 100% CPU time. You will need some kind of delay.
Since you can use socket_select, you can specify a timeout there, using 0% CPU time until there is actually some work to be done:
function selectChangedSockets() {
$read = array($socket1, $socket2); // array of your sockets
$write = NULL;
$except = NULL;
$num_changed_sockets = socket_select($read, $write, $except, NULL);
}
This will wait until one of the sockets in $read has data available. For a server socket, this happens when a new connection is established by a client. For a connected socket, this happens when the client has sent data.
Again, see socket_select for details and examples. Especially the first user contributed note, which uses a while (true), handles new connections, and reads data from clients.
Note however, from the socket_select page, about the 4th parameter:
tv_sec may be zero , causing socket_select() to return immediately. This is useful for polling. If tv_sec is NULL (no timeout), socket_select() can block indefinitely.
My solution is:
if socket server idle 5 second (not receive data), idle mode, relaxes CPU,
<?php
if (!($sock = socket_create(AF_INET, SOCK_DGRAM, 0))) {
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
$server_idle=time();
while (1) {
$buf="";
$r = socket_recvfrom($sock, $buf, 512, MSG_DONTWAIT, $remote_ip, $remote_port);
if ($buf) {
$server_idle=time();
//socket process codes
//.
//.
}
if (time()-$server_idle>5) { // if Server idle 5 second; IDLE Mode!
usleep(100); // IDLE Mode
} else {
// usleep(1); // No IDLE Mode usleep(1) milisecond less CPU process
}
}
?>

Reading data from serial port from Arduino on Windows via PHP. Data not matching serial monitor output

Data I send to the serial port from the Arduino Uno can be viewed exactly as expected in the Arduino serial monitor, but when reading the data from PHP through serproxy in my WAMP environment I am getting some missing or extra characters (often a character that looks like a question mark inside of a black diamond, for example).
I've found similar questions posted, but all of the answers fell short. Often solutions were given for Linux only, or solved only part of the many challenges it takes to even get Windows to read (not write) from a serial port.
I tried the following to get PHP to simply read any serial data:
I first tried the php_serial class suggested, but quickly found out it only allows writing on Windows, and the answer for one of the other stack overflow questions (Serial Communication Arduino to PHP) suggested replacement code only for the Linux portion of the code, not Windows.
The article at Serial comm with PHP on Windows
also mentions limited capacity on Windows for php_serial class and suggests an alternative serial extension (also mentioned here and here), but this would not load on my WAMP environment with PHP 5.4.12 VC9 build when I used the correct matching extension version, added the extension to the correct php.ini, and restarted the server. I received a "Module win_serial is not compiled into PHP" after following all of the steps. If anyone else has had this issue please let me know as I would be willing to look into this again.
Finally, I tried using a program called serproxy which redirects network sockets to and from serial ports. This does work with the caveat that I added a 10uF capacitor on the Arduino's GND and RESET pins to prevent reseting on new serial connections as mentioned at PHP serial port data return from Arduino.
So now, I have my Arduino sending data to my computer via the USB cable, and so long as I am monitoring the data in Arduino's serial monitor, everything looks as it should. The moment I echo out that same data in PHP I begin to see extra or missing data along with the stream. So sending the text "AOK AOK AOK" sometimes becomes "OK?Pz[R" or something similar when echoed out of my PHP script.
Things I've tried to get clean serial data from PHP socket_read():
Messed around with various mb_convert_encoding (like 'ASCII' or 'utf-8')
Setting parity of serial data. I tried setting it to "EVEN" in serproxy config and DOS (ran command of "mode COM4: BAUD=9600 PARITY=E data=8 stop=1 XON=off TO=on" and recieved a valid response/output that command worked as expected)
Verified baud rate is set to 9600 in PHP code and serproxy config
Attempted simple trimming and/or regular expressions to filter out noise, but it doesn't help as some normal alphanumeric characters are randomly mixed in the output as well
Having modified some example socket code for TCP/IP from php.net, I have a PHP script that writes 2048 bits of data from the serial port via serproxy. This page is called via jQuery from another page every 10th of a second and the echoed content is loaded into the contents of a on my main page.
My end goal is to send a stream of either 1's or 0's to be sent to my PHP script to indicate that a should toggle it's background color. I would prefer to be certain those 1's or 0's were not just randomly echoed among the extra characters and truly came from the serial stream itself.
Does anyone know if serproxy is the cause of the adding or removing the unwanted data that I'm seeing in PHP?
The fact that the serial monitor is showing the correct data indicates to me that it's something in the way PHP is receiving or parsing the data.
I'm running out of ideas on what else I could check. Maybe another pair of eyes on this will bring to light something I've overlooked or did incorrectly.
Please see my code below for specific examples below:
serial.html
<!DOCTYPE html>
<head>
</head>
<body>
<div id="serial" name="serial" class="serial"></div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
serial_output.php
<?php
// Set service port to 5334 for serproxy
$service_port = 5334;
// Using localhost address
$address = '127.0.0.1';
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
// Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
}
// Read 2048 bits of data from socket and convert encoding to ASCII
$out = mb_convert_encoding(socket_read($socket, 2048), 'ASCII');
// Filter out anything that is not "AOK"
if(preg_match("/AOK/", $out)){
echo 1;
} else {
// Else output raw data so we can see what was actaully sent
echo $out;
}
// Closing socket...
socket_close($socket);
?>
main.js
// Set #serial background color to red when receiving a "1"
function setBgColor(){
var serial = $('#serial');
// Set #serial background color to red when receiving a "1"
if($('#serial').html() == "1") {
serial.css('background-color','red');
} else {
// Set #serial background to white if we did not receive a "1"
serial.css('background-color', 'white');
}
}
var intervalId = window.setInterval(function(){
$('#serial').load('serial_output.php');
setBgColor();
}, 100);
arduino_serial.ino
#include <avr/pgmspace.h>
void setup() {
// Initialize serial and wait for port to open:
// Currently I have parity on my serial port set to "EVEN" hence SERIAL_8E1
Serial.begin(9600, SERIAL_8E1);
}
void loop() {
Serial.println("AOK");
}
So I ran your code and had the same issues with my Arduino and an accelerometer. I found three ways to alleviate the issue.
First is just to error check your data in terms of what you expected. If the data doesn't match what you expected, just discard it. If you are getting data 10x a second, I suppose you can afford to lose some. [BTW: serproxy crashes on me in under 10 minutes, so it's of limited use to me].
Second, just delay the data on the Arduino side. Apparently the data loss is a "known issue" regarding Arduinos and serial ports. This person's site at martinmelchior.be has some code to delay the data stream being sent from the Ardunio;
`void slowSerialPrint(char text[]) {
for ( int i ; i < strlen(text) ; i ++ ) {
Serial.print(text[i]);
delay(5);
}
} `
Scroll down to "But not so fast..." to find that snippet.
Finally, you could just try what many others are doing and buy a cheap wireless router and use that as your own inexpensive wi-fi shield. Which, oddly enough is what the site linked above does!
It is also good to note that that router's maximum current draw at 5V is 185mA (OpenWrt boot), average current draw with WiFi at 18dBm is 100mA, without WiFi 80mA. Hence the average router power consumption is 0.5W, which is incredibly low.
Also, thank you for the code you posted, I was searching for a way to do exactly what you were doing, so I implemented your code, hit the same wall, solved my issue by slowing down the Arduino's output in javascript and discarding dirty data, then branched out into other options.
tl;dr: I don't think there is a simple solution.

Webbased chat in php without using database or file

I am trying to implement a realtime chat application using PHP . Is it possible to do it without using a persistent data storage like database or file . Basically what I need is a mediator written in PHP who
accepts messages from client browsers
Broadcasts the message to other clients
Forgets the message
You should check out Web Sockets of html5. It uses two way connection so you will not need any database or file. Any chat message comes to the server will directly sent to the other users browser without any Ajax call. But you need also to setup web socket server.
Web sockets are used in many real time applications as well. I am shortly planing to write full tutorial on that. I will notify you.
Just tried something I had never done before in response to this question. Seemed to work but I only tested it once. Instead of using a Socket I had an idea of using a shared Session variable. Basically I forced the Session_id to be the same value regardless of the user therefore they are all sharing the same data. From a quick test it seems to work. Here is what I did:
session_id('12345');
session_start();
$session_id = session_id();
$_SESSION['test'] = $_SESSION['test'] + 1;
echo "session: {$session_id} test: {$_SESSION['test']} <br />";
So my thought process was that you could simply store the chat info in a Session variable and force everyone regardless of who they are to use a shared session. Then you can simply use ajax to continually reload the current Session variable, and use ajax to edit the session variable when adding a message. Also you would probably want to set the Session to never expire or have a really long maxlifetime.
As I said I just played around with this for a few minutes to see if it would work.
You will want to use Sockets. This article will cover exactly what you want to do: http://devzone.zend.com/209/writing-socket-servers-in-php/
When I tried to solve the same problem, I went with Nginx's Push Module. I chose to go this way since I had to support older browsers (that usually won't support WebSockets) and had no confidence in setting up an appropriate solution like Socket.io behind a TCP proxy.
The workflow went like this:
The clients connect through long-polling to my /subscriber location, which is open to all.
The /publisher location only accepts connections from my own server
When a client subscribes and talks, it basically just asks a PHP script to handle whatever data is sent.
This script can do validation, authorization, and such, and then forwards (via curl) the message in a JSON format to the /publisher.
Nginx's Push Module handles sending the message back to the subscribers and the client establishes a new long-polling connection.
If I had to do this all over again, then I would definitely go the Socket.io route, as it has proper fallbacks to Comet-style long-polling and has great docs for both Client and Server scripts.
Hope this helps.
If you have a business need for PHP, then adding another language to the mix just means you then have two problems.
It is perfectly possible to run a permanent, constantly-running daemonised PHP IRCd server: I know, because I've done it, to make an online game which ran for years.
The IRC server part I used is a modified version of WaveIRCd:
http://sourceforge.net/projects/waveircd/
I daemonised it using code I made available here:
http://www.thudgame.com/node/254
That code might be overkill: I wrote it to be as rugged as I could, so it tries to daemonise using PHP's pcntl_fork(), then falls back to calling itself recursively in the background, then falls back to perl, and so on: it also handles the security restrictions of PHP's safe mode in case someone turns that on, and the security restrictions imposed by being called through cron.
You could probably strip it down to just a few lines: the bits with the comments "Daemon Rule..." - follow those rules, and you'll daemonize your process just fine.
In order to handle any unexpected daemon deaths, etc, I then ran that daemoniser every minute through cron, where it checked to see if the daemon was already running, and if so either quietly died, or if the daemon was nonresponsive, killed it and took its place.
Because of the whole distributed nature of IRC, it was nicely rugged, and gave me a multiplayer browser game with no downtime for a good few years until bit-rot ate the site a few months back. I should try to rewrite the front end in Flash and get it back up again someday, when I have time...
(I then ran another daemonizer for a PHP bot to manage the game itself, then had my game connect to it as a java applet, and talk to the bot to play the game, but that's irrelevant here).
Since WaveIRCd is no longer maintained, it's probably worth having a hunt around to find if anyone else has forked the project and is supporting it.
[2012 edit: that said, if you want your front end to be HTML5/Javascript, or if you want to connect through the same port that HTTP connects through, then your options are more limited than when using Flash or Java. In that case, take the advice of others, and use "WebSockets" (poor support in most current browsers) or the "Socket.io" project (which uses WebSockets, but falls back to Flash, or various other methods, depending what the browser has available).
The above is for situations where your host allows you to run a service on another port. In particular, many have explicit rules in their ToS against running an IRCd.]
[2019 edit: WebSockets are now widely supported, you should be fine using them. As a relevant case study, Slack is written in PHP (per https://slack.engineering/taking-php-seriously-cf7a60065329), and for some time supported the IRC protocol, though I believe that that has since been retired. As its main protocol, it uses an API based on JSON over WebSockets (https://api.slack.com/rtm). This all shows that a PHP IRCd can deliver enterprise-level performance and quality, even where the IRC protocol is translated to/from another one, which you'd expect to give poorer performance.]
You need to use some kind of storage as a buffer. It IS plausable not to use file or db (which also uses a file). You can try using php's shared memory functions, but I don't know any working solution so you'll have to do it from scratch.
Is it possible to do it without using a persistent data storage like
database or file?
It is possible but you shouldn't use. Database or file based doesn't slows down chat. It will be giving additional security to your chat application. You can make web based chat using ajax and sockets without persistent data.
You should see following posts:
Is database based chat room bad idea?
Will polling from a SQL DB instead of a file for chat application increase performance?
Using memcached as a database buffer for chat messages
persistent data in php question
https://stackoverflow.com/questions/6569754/how-can-i-develop-social-network-chat-without-using-a-database-for-storing-the-c
File vs database for storage efficiency in chat app
PHP is not a good fit for your requirements (in a normal setup like apache-php, fastcgi etc.), because the PHP script gets executed from top to bottom for every request and cannot maintain any state between the requests without the use of external services or databases/files (Except e.g. http://php.net/manual/de/book.apc.php, but it is not intended for implementing a chat and will not scale to multiple servers.)
You should definitely look at Node.js and especially the Node.js module Socket.IO (A Websocket library). It's incredibly easy to use and rocks. Socket.IO can also scale to multiple chat servers with an optional redis backend, which means it's easier to scale.
Trying to use $_SESSION with a static session id as communication channel is not a solution by the way, because PHP saves the session data into files.
One solution to achieving this is by writing a PHP socket server.
<?php
// Set time limit to indefinite execution
set_time_limit (0);
// Set the ip and port we will listen on
$address = '192.168.0.100';
$port = 9000;
$max_clients = 10;
// Array that will hold client information
$clients = Array();
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die('Could not bind to address');
// Start listening for connections
socket_listen($sock);
// Loop continuously
while (true) {
// Setup clients listen socket for reading
$read[0] = $sock;
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] != null)
$read[$i + 1] = $client[$i]['sock'] ;
}
// Set up a blocking call to socket_select()
$ready = socket_select($read,null,null,null);
/* if a new connection is being made add it to the client array */
if (in_array($sock, $read)) {
for ($i = 0; $i < $max_clients; $i++)
{
if ($client[$i]['sock'] == null) {
$client[$i]['sock'] = socket_accept($sock);
break;
}
elseif ($i == $max_clients - 1)
print ("too many clients")
}
if (--$ready <= 0)
continue;
} // end if in_array
// If a client is trying to write - handle it now
for ($i = 0; $i < $max_clients; $i++) // for each client
{
if (in_array($client[$i]['sock'] , $read))
{
$input = socket_read($client[$i]['sock'] , 1024);
if ($input == null) {
// Zero length string meaning disconnected
unset($client[$i]);
}
$n = trim($input);
if ($input == 'exit') {
// requested disconnect
socket_close($client[$i]['sock']);
} elseif ($input) {
// strip white spaces and write back to user
$output = ereg_replace("[ \t\n\r]","",$input).chr(0);
socket_write($client[$i]['sock'],$output);
}
} else {
// Close the socket
socket_close($client[$i]['sock']);
unset($client[$i]);
}
}
} // end while
// Close the master sockets
socket_close($sock);
?>
You would execute this by running it through command line and would always have to run for your PHP clients to connect to it. You could then write a PHP client that would connect to the socket.
<?php
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
You would have to use some type of ajax to call with jQuery posting the message to this PHP client.
http://devzone.zend.com/209/writing-socket-servers-in-php/
http://php.net/manual/en/function.fsockopen.php
Better use a node.js server for this. WebSockets aren't cross-browser nowadays (except socket.io for node.js that works perfect)
in short answer, you can't.
the current HTTP/HTML implementation doesn't support the pushstate so the algorithm of your chat app should follow :
A: sent message
B,C,D: do while a new message has been sent get this message.
so the receivers always have to make a new request and check if a new message has been sent. (AJAX Call or something similar )
so always there are a delay between the sent event and the receive event.
which means the data must be saved in something global, like db or file system.
take a look for :
http://today.java.net/article/2010/03/31/html5-server-push-technologies-part-1
You didn't say it had to all be written it PHP :)
Install RabbitMQ, and then use this chat implementation built on top of websockets and RabbitMQ.
Your PHP is pretty much just 'chat room chrome'. It's possible most of your site would fit within the 5 meg limit of offline HTML5 content, and you have a very flexible (and likely more robust than if you did it yourself) chat system.
It even has 20 messages of chat history if you leave the room.
https://github.com/videlalvaro/rabbitmq-chat
If You need to use just PHP, then You can store chat messages in session variables, session could be like object, storing a lot of information.
If You can use jQuery then You could just append paragraph to a div after message has been sent, but then if site is refreshed, messages will be gone.
Or combining, store messages in session and update that with jQuery and ajax.
Try looking into socket libraries like ZeroMQ they allow for instant transport of the message, and are quicker than TCP, and is realtime. Their infrastructure allows for instant data send between points A and B, without the data being stored anywhere first (although you can still choose to).
Here's a tutorial for a chat client in ZeroMQ

How to implement event listening in PHP

here is my problem: I have a script (let's call it comet.php) whic is requsted by an AJAX client script and wait for a change to happen like this:
while(no_changes){
usleep(100000);
//check for changes
}
I don't like this too much, it's not very scalable and it's (imho) "bad practice"
I would like to improve this behaviour with a semaphore(?) or anyway concurrent programming
technique. Can you please give me some tips on how to handle this? (I know, it's not a short answer, but a starting point would be enough.)
Edit: what about LibEvent?
You can solve this problem using ZeroMQ.
ZeroMQ is a library that provides supercharged sockets for plugging things (threads, processes and even separate machines) together.
I assume you're trying to push data from the server to the client. Well, a good way to do that is using the EventSource API (polyfills available).
client.js
Connects to stream.php through EventSource.
var stream = new EventSource('stream.php');
stream.addEventListener('debug', function (event) {
var data = JSON.parse(event.data);
console.log([event.type, data]);
});
stream.addEventListener('message', function (event) {
var data = JSON.parse(event.data);
console.log([event.type, data]);
});
router.php
This is a long-running process that listens for incoming messages and sends them out to anyone listening.
<?php
$context = new ZMQContext();
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind("tcp://*:5555");
$pub = $context->getSocket(ZMQ::SOCKET_PUB);
$pub->bind("tcp://*:5556");
while (true) {
$msg = $pull->recv();
echo "publishing received message $msg\n";
$pub->send($msg);
}
stream.php
Every user connecting to the site gets his own stream.php. This script is long-running and waits for any messages from the router. Once it gets a new message, it will output this message in EventSource format.
<?php
$context = new ZMQContext();
$sock = $context->getSocket(ZMQ::SOCKET_SUB);
$sock->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, "");
$sock->connect("tcp://127.0.0.1:5556");
set_time_limit(0);
ini_set('memory_limit', '512M');
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
while (true) {
$msg = $sock->recv();
$event = json_decode($msg, true);
if (isset($event['type'])) {
echo "event: {$event['type']}\n";
}
$data = json_encode($event['data']);
echo "data: $data\n\n";
ob_flush();
flush();
}
To send messages to all users, just send them to the router. The router will then distribute that message to all listening streams. Here's an example:
<?php
$context = new ZMQContext();
$sock = $context->getSocket(ZMQ::SOCKET_PUSH);
$sock->connect("tcp://127.0.0.1:5555");
$msg = json_encode(array('type' => 'debug', 'data' => array('foo', 'bar', 'baz')));
$sock->send($msg);
$msg = json_encode(array('data' => array('foo', 'bar', 'baz')));
$sock->send($msg);
This should prove that you do not need node.js to do realtime programming. PHP can handle it just fine.
Apart from that, socket.io is a really nice way of doing this. And you could connect to socket.io to your PHP code via ZeroMQ easily.
See also
ZeroMQ
ZeroMQ PHP Bindings
ZeroMQ is the Answer - Ian Barber (Video)
socket.io
It really depends on what you are doing in your server side script. There are some situations in which your have no option but to do what you are doing above.
However, if you are doing something which involves a call to a function that will block until something happens, you can use this to avoid racing instead of the usleep() call (which is IMHO the part that would be considered "bad practice").
Say you were waiting for data from a file or some other kind of stream that blocks. You could do this:
while (($str = fgets($fp)) === FALSE) continue;
// Handle the event here
Really, PHP is the wrong language for doing stuff like this. But there are situations (I know because I have dealt with them myself) where PHP is the only option.
As much as I like PHP, I must say that PHP isn't the best choice for this task.
Node.js is much, much better for this kind of thing and it scales really good. It's also pretty simple to implement if you have JS knowledge.
Now, if you don't want to waste CPU cycles, you have to create a PHP script that will connect to a server of some sort on a certain port. The specified server should listen for connections on the chosen port and every X amount of time check for whatever you want to check (db entries for new posts for example) and then it dispatches the message to every connected client that the new entry is ready.
Now, it's not that difficult to implement this event queue architecture in PHP, but it'd take you literally 5 minutes to do this with Node.js and Socket.IO, without worrying whether it'll work in majority of browsers.
I agree with the consensus here that PHP isn't the best solution here. You really need to be looking at dedicated realtime technologies for the solution to this asynchronous problem of delivering data from your server to your clients. It sounds like you are trying to implement HTTP-Long Polling which isn't an easy thing to solve cross-browser. It's been tackled numerous times by developers of Comet products so I'd suggest you look at a Comet solution, or even better a WebSocket solution with fallback support for older browsers.
I'd suggest that you let PHP do the web application functionality that it's good at and choose a dedicated solution for your realtime, evented, asynchronous functionality.
You need a realtime library.
One example is Ratchet http://socketo.me/
The part that takes care of the pub sub is discussed at http://socketo.me/docs/wamp
The limitation here is that PHP also needs to be the one to initiate the mutable data.
In other words this wont magically let you subscribe to when MySQL is updated. But if you can edit the MySQL-setting code then you can add the publish part there.

How to keep Node.js from splitting socket messages into smaller chunks

I've got a chat program which pushes JSON data from Apache/PHP to Node.js, via a TCP socket:
// Node.js (Javascript)
phpListener = net.createServer(function(stream)
{
stream.setEncoding("utf8");
stream.on("data", function(txt)
{
var json = JSON.parse(txt);
// do stuff with json
}
}
phpListener.listen("8887", 'localhost');
// Apache (PHP)
$sock = stream_socket_client("tcp://localhost:8887");
$written = fwrite($sock, $json_string);
fclose($sock);
The problem is, if the JSON string is large enough (over around 8k), the output message gets split into multiple chunks, and the JSON parser fails. PHP returns the $written value as the correct length of the string, but the data event handler fires twice or more.
Should I be attaching the function to a different event, or is there a way to cache text across event fires, in a way that won't succumb to race conditions under heavy load? Or some other solution I haven't thought of?
Thanks!
You should try using a buffer, to cache the data, as Node.js tends to split data in order to improve performance.
http://nodejs.org/api.html#buffers-2
you can buffer all your request, and then call the function with the data stored at it.
TCP sockets don't handle buffering for you. How could it? It doesn't know what application layer protocol you are using and therefore has no idea what a "message" is. It is up to you to design and implement another protocol on top of it and handle any necessary buffering.
But, Node.js does have a built in application layer protocol on top of TCP that does automatically handle the buffering for you: the http module. If you use the http module instead of the tcp module for this you won't need to worry about packet fragmentation and buffering.

Categories