4

This may be a silly question to some who have wrapped their head around it already and maybe I just need more .

Question: Whether using or 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 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 or 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 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.

Jesse
  • 2,790
  • 1
  • 20
  • 36
  • The purpose of a websocket/socket in general is to keep a constant connection that is always open, So in the event of say a chat program.. The clients on receive data when it is available, they save bandwidth by not having to poll/post to the server every few seconds to appear responsive. The simply wait & have a received event triggered. In regards to monitoring a server side file, this requires polling. But the server would itself poll the file and send an update to all clients, instead of all clients checking with the server every few seconds, Websockets here would still save you bandwidth. – Angry 84 Oct 11 '15 at 03:33
  • I fully understand the purpose of websockets. The question is regarding polling for new content and how the logic behind that works. – Jesse Oct 11 '15 at 03:37
  • As said, you would still have PHP poll the file locally and then notify the clients when a change is detected, as to how you poll the file. That can vary, You could use a CRON job but would require the socket server running on another threat/php script.Possibly using http://php.net/manual/en/function.fam-monitor-file.php but otherwise i would just have a something like the FAM function running in the main loop of the socket server, If detected then do a send to all message. – Angry 84 Oct 11 '15 at 03:48
  • To clarify, you are answering this part "Question: Whether using websockets or ajax it seems like there is still some polling happening. Is this correct?" with "yes" ? – Jesse Oct 11 '15 at 03:50
  • For pure client and server communication, there is no polling. For PHP to be able to detect a change in a file on the server side, yes there would be some form of polling. having 1000 clients all ajax poll your server and each of those triggering the server to check = 1000 checks for a file. Websocket would just be the server polling in its own loop and doing a send message when true.. So sockets simply are better here for your need.. As for the file, its just standard php code to check if a file has changed. – Angry 84 Oct 11 '15 at 03:53
  • Whilst I understand the question topics are different. I asked a question regarding sockets & polling a long time ago. I believe ge answer bradley provided might be of some help. http://stackoverflow.com/questions/25456898/sockets-polling-socket-less-results mainly shed a slight light on things.. a little long shot which could pay off – Daryl Gill Oct 11 '15 at 03:56
  • @mayhem I see what you are saying, I do. I am just not grasping how this is done. So I should remove the `sleep` and let PHP hit that file in an endless loop, or do I need the sleep (a form of polling really)? – Jesse Oct 11 '15 at 03:56
  • Posted answer, taking into account my comments.. But using your PHP example. – Angry 84 Oct 11 '15 at 04:00
  • Further note, in general when it comes to monitoring a file for changes.. Every OS/Platform in the end, will use a form of polling.. Even languages or system hooks/handles all at some point run a loop to monitor.. So this is technically a correct way/means of doing it.. Just PHP scripts can be,, a little unforgiving when left in endless loops – Angry 84 Oct 11 '15 at 04:18
  • Why are you watching a file of all things? Who's editing the file? Do you have control over the process of the editing? Can you make sure that whenever the file is changed, an event is triggered or published (i.e. using Redis for Pub/Sub or using a private API)? - You general question is answered below, Websockets allow you to avoid polling altogether... but I'm not sure I can help if I don't know what you're actually trying to do. – Myst Oct 12 '15 at 05:21
  • Thanks. Been thinking about this in the context of a Mojolicious application. Currently, I've just used a (spurious) send, few seconds interval as a heartbeat to provoke a pseudo-poll. But this is ugly, now going to work out something server-side with the database. – Hugh Barnard May 17 '21 at 11:14

3 Answers3

0

I would suggest something similar to this initially.

$sFile = "/my/file/test.txt";
$timeMod = filemtime($sFile);
while(true) {
    if (filemtime("SomeFileHere.txt")!==$timeMod ) {
        $timeMod = filemtime($sFile);
        // File has changed, update variable with new timestamp
        $this->send($client, file_get_contents($sFile));
    } else {
        // No change, do nothing here.
    }
    sleep(1);
}

Basically before you loop, you get the last modified date.. If in the loop it has changed, we update the variable and send an alert at that time.

If trying to make something similar to this work in real world without any load problems, i would have a single PHP file running in a loop (dameon possibly).. Which would monitor the file every second in a simple loop like above.. If there is a change, i would have it notify another PHP script/thread to send out the content to all clients.

If the same file gets send to all clients, this wont be to bad.. As you can use a send to all function.. But if its different per client (like their own history/log).. It would require processing per client which will being a performance hit a little.

To further future proof stuff like this, you would record down the time that a client last received the files content and limit how long before it can be sent again.. So the client only gets a new copy after 10 seconds min, anything less and it just ignores.

To what scope/scale & type of project is this?

Currently my python server can received a request from 20,000 clients and process their data and respond back all within a second each... (GPS Processing). While i am not sending anything over a kilobyte each time, the ability to thread and queue in python will make it a much better approach and can handle this many clients in a single instance. with only using about 130mb of ram with no memory leaks over time

PHP i personally feel should not run for ever in a loop, it just does not feel like how it should be used.

Angry 84
  • 2,935
  • 1
  • 25
  • 24
  • Totally a valid way to address this using my example (this only works in the example, which is not a real task I am trying to perform, it is just an example). I do not think you are fully understanding the question if I can be honest. – Jesse Oct 11 '15 at 04:01
  • Explain further? Can understand if we are not on the same level atm – Angry 84 Oct 11 '15 at 04:01
  • I am not specifically looking for a specific solution to watching a text file. – Jesse Oct 11 '15 at 04:03
  • PHP will wait for a task to finish before it continues onto the next line of code, it does have threading abilities but is not ideal to use them.. Basically with this example, it would work... But each client would be queuing up and over time this would lag behind. For a multiclient monitor server i have used python which allows me to use true events/control over each client with standard queues. PHP will be very limited here and is not an ideal language/solution for this type of purpose. (Personal experience here) – Angry 84 Oct 11 '15 at 04:04
0

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).

Myst
  • 18,516
  • 2
  • 45
  • 67
  • 1
    I get it now. By sleeping on it and seeing your response about visiting in 2 browser windows. I suppose I was thinking about it the old fashioned one user at a time. Instead of watching for a change, when one user sends a change in, I update all clients. I knew I was thinking about this the wrong way. – Jesse Oct 12 '15 at 11:42
  • I realize my answer might be outdated (as I wrote it 5 years ago).. but why downvote it in November 2020 (5 years later)? And why not leave a comment, so I can fix whatever's "wrong" (if anything)... ‍♂️ – Myst Nov 21 '20 at 01:59
  • I can only assume someone hot searching for websocket php stuff with the php tags and saw non-copy-pastable ruby code – Jesse Dec 05 '20 at 23:31
-4

Event based programming is needed here. It would be much easier to use a library that handles events for you. PHP is not the best tool for this type of programming, but there may still be a library for it.

One solution would be to have a nodejs/socket.io server, and your php processes could send it a message when something interesting happens. The nodejs server would then pass that along to the clients.

Jason Rice
  • 1,686
  • 1
  • 12
  • 17
  • 4
    I was genuinely hoping to not receive a node js response for a non node js question. I am aware of node js, this question is about PHP and not specifically about libraries. Specifically it is about how polling for new content works, in PHP, no library, not in node JS. This is more suited as a comment – Jesse Oct 11 '15 at 03:42
  • 3
    I cant stand the fact that everything now points people to node.js.. Making a websocket server in PHP is easy, it just requires people to be able to program vs installing another damn lib... Python ended up being my choice for a websocket server as more control and lower resources required for it. – Angry 84 Oct 11 '15 at 03:51
  • 3
    @Mayhem - I could not agree more. It is like seeing a Javascript question where the first answer is "You should use jquery". – Jesse Oct 11 '15 at 03:52
  • You asked for a way to handle 'real time' without polling, and I suggested an event based model. PHP does have a wrapper for inotify, if you are dealing strictly with watching a file. The biggest problem with polling here is that you are hitting the disk to read a file, and I'm sure you're aware that IO can be a big bottle-neck. – Jason Rice Oct 11 '15 at 04:01
  • Javascript is an event based programming language, hence the suggestion. – Jason Rice Oct 11 '15 at 04:02
  • The question is not specific to a text file (which is why it was labeled as Example (not real project), but is specific to the logic of how PHP handles this. – Jesse Oct 11 '15 at 04:05