Send notification from server to client on server event
Asked Answered
T

3

16

How can I send a message from server to client with PHP, avoiding extraneous Ajax calls.

Here is the idea:

  1. User: Alice makes a change which gets sent to the server.

  2. The Server then checks to see which users are not up to date, and if not calls some code to send the information pertaining to the change to Bob (who is not up to date in this case).

How do I send Bob the message?

Thorlie answered 22/6, 2014 at 19:29 Comment(12)
If you're interested in the exact tools and technologies Stack Exchange uses, then this question on Meta Stack Exchange will be of use to you. As far as actually implementing something that would have similar functionality, this question is way too broad.Kitchenware
Look into Ajax.Curiosity
@MatthewStrawbridge Read the post, I talk about why that doesn't work.Thorlie
Sorry, still too broad and open-ended. The question might not be a good fit for Stack Overflow no matter how you phrase it, but you can try asking another question on Meta Stack Overflow to see if anyone else has any ideas about how to make it viable here.Burtie
@Thorlie What you want are websockets (falling back on a longpoll using ajax only in ancient browsers if you wish to support them). In case you aren't able to get your question re-opened, I'd look into that, at which point your questions will probably be implementation specific and much easier to ask.Oracle
If Stack Overflow is not the right place for this, does anyone have suggestion as to where that place is?Thorlie
I re-opened this as I think it's answerable, and a great opportunity for someone to kill an answer with a comprehensive overview on websockets, and how to fall back on longpolls if they aren't available (I thought we had that, but I can't find it). The community can override me, though (associated meta discussion)Oracle
@TimPost Thank You for the info on Web Sockets! That is Exactly what I needed!Thorlie
It seems what might be useful is a publish/subscribe (pubsub) pattern or implementation for PHP. Note this isn't a lmgtfy link, it's a (possible) clarification of what you might be after.Protease
Related?: What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?.Burtie
Related?: HTML5 WebSocket vs Long Polling vs AJAX vs WebRTC.Burtie
Related?: How can I send and receive WebSocket messages on the server side?.Burtie
C
23

You can use Server Sent Events.

These are the often over looked cousin of websockets that are lighter weight and one way. They essentially allow the client to wait for a message from the server (which you can then respond to via a different channel such as AJAX)

Example Client Code:

var source = new EventSource('/newFile');

source.addEventListener('message', function(e) {
  // Use AJAX and pull new file here
}, false);

Unfortuantely it seems (of course) that there is no IE support. One could use a library such as EventSource HQ to support cross browser server sent events. It will abstract away needing to handle the devil's browser.

Catsup answered 23/6, 2014 at 2:36 Comment(1)
Polyfills for w3.org/TR/eventsource - github.com/Yaffle/EventSource & github.com/remy/polyfills/blob/master/EventSource.js . Of course, there would be few more but of the above works well with IE.Derringer
T
15

What you are looking for is something which is (now) quite common, and is sometimes called "real-time web". It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.

This is possible through a couple of new mechanisms which are supported by newest browsers (and servers), and by some other mechanisms which weren't really designed to do that, but which can be used as "hacks" to make it work.

The first thing you have to understand is that what you are asking for (a server "pushing" a message to a client) is not how the web (or, at least, http) is (or better, was) intended to work. The classic web is stateless, request-response, half-duplex: the client initiates the communication, opens a connection to the server, the server serve something, and the connection is closed. And there used to be no way for a server to send a message to a web client: the client (i.e. your browser) should support the reverse model (offering an endpoint on which it listens), becoming effectively a server.

This is, more or less, what newer standards like WebSockets offer (another standard worth mentioning is Server-sent events (SSE); however, its support is even scarcer than WebSockets, and they seem more apt to "stream" content than sending single messages).

Unlike HTTP, WebSocket provides full-duplex communication (either party can initiate it), which is what you are looking for. The correct version of the WebSocket protocol (an older, buggy implementation exist in some browsers) is implemented in Firefox 6, Safari 6, Google Chrome 14, Opera 12.10 and Internet Explorer 10.

So, what if your browser does not support WebSockets? You have to use those "tricks" I mentioned earlier. Those "trick" fall under the unbrella of Push technologies.

In particular, a common technique is long polling. Like the name says, it is not "push"; long polling is polling, i.e. a "pull" technique, but it allows to emulate a push mechanism. With long polling, the client requests information from the server exactly as in a normal AJAX call, except it issues its HTTP/S requests (polls) at a much slower frequency.

Upon connection, the server (your server, your API: a servlet, an HTTP handler, a REST controller, whatever! It is usually the same mechanism with which you provide support for your standard AJAX calls) sends some info if there is already an update already available; if there is nothing new, instead of sending an empty response, it holds the request open and waits for response information to become available.

You have a "traditional" client-initiated request, but that is put "on hold" until there is something that the server wants to communicate to you. Once there is something, the server sends a response (via the HTTP channel, still open!) to the client, completing the open HTTP Request.

Other techniques (like using sockets provided by plugins - Silverlight, Java applets, Flash..) can be used, but then again for exploiting them you need the correct client (brower/plugin combo).

Of course, you could implement all this stuff by yourself. And I encourage you to try as a learning exercise.

For your production code, you better use a library that encapsulates all these concepts and techniques, like SignalR (for ASP.NET) Ratchet (for PHP), Signal.IO (for node.js), Faye (for Ruby).... Some of these libraries will implement more than one technique, choose the best technique based on the client, falling back to other ones automatically. They really spare you a lot of trouble!

Townspeople answered 24/6, 2014 at 7:32 Comment(0)
C
8

As was said in the comments the technology that you are looking for is WebSockets. They are a way for you to have a socket (a unix lingo term for essential a bidrectional pipe) between your server and the web browsing client.

While one can work with the raw websocket api. I prefer to use a library like Socket.IO to abstract away the nasty details for me.

After installing the package as one normally would (assuming you're using node) Socket.IO gives you many different easy ways such as events and broadcasts in integrate into your application. You can also just use it as a just a cross browser websocket (it implements fallback long polling for browsers that don't support websockets).

For your case you would want to send a message from the server to the client when ever a file is changed on the server.

One the server side (Node.js):

var io = require('socket.io').listen(80);

io.sockets.on('connection', function (socket) {
  socket.on('message', function () { });
  socket.on('disconnect', function () { });

  // more stuff here
  if(somethingChanged) {
    socket.send(JSON.stringify({changed: true, file: 'file1.txt', newContent: 'Im fresh off the press yo!'});
  }
});

For the client:

<script>
  var socket = io('http://localhost/');
  socket.on('connect', function () {
    socket.send('anything-new');

    socket.on('message', function (msg) {
      if(JSON.parse(msg).changed) {
        // Do stuff here
      }
    });
  });
</script>

While that is a very bare example it's hopefully enough to get you started.

Catsup answered 23/6, 2014 at 2:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.