This may be a silly question to some who have wrapped their head around it already and maybe I just need more coffee.
Question: Whether using websockets or ajax it seems like there is still some polling happening. Is this correct?
Example (not real project): I want to keep an eye on a text file. Unless I am missing something (more coffee?), aren't I still having to either a) Ask the server if there is an update, or b) Tell the page I have an update; Through either sleeping the PHP code for a set time or having a setTimeout loop on the client side.
Things I do understand: I definitely see a benefit already with talking back and forth between server and page. I see that I am not sending http requests. So I see benefits.
Details: I have always just used xmlhttprequest so I decided to check out this whole websockets thing as from what I thought I understood, is that data is sent to the client in real time, but, like stated above, unless I am missing something or some logic here, it seems like I still have to either tell php or javascript to check in intervals for data, otherwise data is being sent in an endless loop (imagine making a call to mysql).
Maybe my logic in my code is all kinds of bad. You are welcome to view it. From all of the examples I found, everyone seems to just run an infinite loop in PHP
PHP (Minus all of the connection jargon)
while(true) {
// update once a second
$this->send($client, file_get_contents('/my/file/test.txt'));
sleep(1);
}
Javascript
var websocket = new WebSocket( "ws://mysite.com:12345" );
websocket.onmessage = function( str ) {
console.log( str.data );
};
I am just not grasping the logic on this on how I can make it real time without some sort of polling. Maybe this is how it is supposed to work.
I do understand that if I remove the sleep from the php code things get much more real time, too much, but this seems like it would infinitely poll the file in the example above and that doesn't seem right.
Edit: To clarify, I am not specifically looking for a specific solution to watching a text file. You may have thought this if you skimmed the question.
Edit: Future visitors, the answer to this is: instead of specifically watching for changes, when a user sends a change in, you send the change to open connections.
Websockets allow you to avoid polling altogether, as long as you control all the events (or Sub/Pub to a external events).
As to your example, if YOU control the action of writing to the file, than you can invoke a websocket "broadcast" or "publish" this event.
In this way, you avoid polling altogether.
Since I abhor working with PHP (no offense, I just had my fill of it), Here's a quick Ruby example using the Plezi Real-Time Framework.
In this example we use a simple touch
method to perform an action. Although I'm not really touching a file, you can experience that the use of the API allowed me to control the event and broadcast to the other users - no polling involved.
The same would be true if I were subscribing to external events.
To run this example, install the plezi
gem using [sudo] gem install plezi
(depending if you need sudo
or not and your system) and open the IRB terminal using the irb
command from your terminal. Than paste the following code:
require 'plezi'
class RootController
def index
%{<html><head>
<script>
var websocket = NaN;
function connect() { websocket = new WebSocket( (window.location.protocol.match(/https/) ? 'wws' : 'ws') + '://' + window.location.hostname + (window.location.port == '' ? '' : (':' + window.location.port) ) + "/" ); }
function init()
{
connect()
websocket.onopen = function(evt) { WriteMessage("(Connected and waiting for messages)", "connection") };
websocket.onclose = function(evt) { WriteMessage("(Disconnected. messages will be lost)", "connection");connect(); };
websocket.onmessage = function(evt) {
WriteMessage(evt.data, "");
};
websocket.onerror = function(evt) { WriteMessage(evt.data, 'error'); };
}
function WriteMessage( message, message_type )
{
if (!message_type) message_type = 'received'
var msg = document.createElement("p");
msg.className = message_type;
msg.innerHTML = message;
document.getElementById("output").appendChild(msg);
}
function Send(message)
{
WriteMessage(message, 'sent');
websocket.send(message);
}
window.addEventListener("load", init, false);
</script></head>
<body>
<p>Messages should show up here:</p>
<div id=output></div>
</body>
</html>
}
end
def touch
FileController.touch
"You Touched the file, a message should be sent to the web browser windows."
end
def on_open
subscribe :file_notifications
end
def on_message data
end
def self.push_update_event
publish :file_notifications, "The file was updated."
"Touched - Ok".freeze
end
end
class FileController
def self.touch
puts "INFO: A file should be touched.. you can do whatever you feel like here..."
RootController.push_update_event
end
end
class APIController
def touched
RootController.push_update_event
end
end
Plezi.route '/', RootController
Plezi.route '/api', APIController
exit # the server will start once you exit the irb terminal
Now visit, in two different browser windows:
Or, you can even "edit the file" (virtually) using an external script and then visit http://localhost:3000/api/touched to inform all the users about that action (authentication isn't shown here, but should be added).