Search code examples
javascriptphpwebsocketphpwebsocket

Websockets - Getting Data (Polling?)


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.


Solution

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