Persistent Full Duplex Client-Server Connection via Web Socket
RIA is considered as one of the mostly particular to the modern Web feature, and often stands for the trend, according to which web-applications tend to desktop applications. Nonetheless the approach is very relative. Overwhelming majority of “rich” web-applications is still built on the “request-response” model. I.e. events of the client side can be reflected on the sever side, but not vice-versa. In order to make such a trivial thing as a chat, you have to go with tricks. There are different techniques to emulate bi-directional connections. Usually solutions of the kind are called Comet, thanks to Alex Russell of Dojo.
Regarding to cometdaily.com here is the list of known tricks:
- Long polling – the server doesn’t respond on the XHR-request immediately, but only when the queue receives the event, addressed to the requesting source. E.g. client requests the update of the chat window, but server answers on the request only when state of the DB related to the chat has been changed.
- Forever frame – creates iframe, in which the server constantly appends events by their arrival.
- script tags - dynamically generated JS-blocks, what allows cross-domain communications.
- ActiveXObject(”htmlfile”) – the method available in IE which uses ActiveX.
- [JSONRequest object |www.json.org/JSONRequest.html] – makes bi-directional channel by two simultaneous requests (one for the transmission ad one for the receive) . Moreover , Flash embeddings ad Java-applets can be used . Hah, even such tricky way as Forever GIF.
To fulfill the picture I would add from my side several high-level solutions:
- Bayeux protocol – allows event exchange by the model: one client – many servers, one server – many clients. Particulary it’s used in CometD project
- [BOSH protocol](http://xmpp.org/extensions/xep-0124.html XMPP standards foundation “BOSH protocol”) - eulates duplex stream of data between browser and serve, using two synchronous HTTP-conections.
- APE (Ajax Push Engine) – light-weight open source push-server, which is used in MooTools, Dojo, jQuery.
Whatsoever, any of those approaches is more or less but a workaround, when everybody wants a native solution. Guys of HTML5 working group apparently got the issue very well, so the HTML5 standard has such method as Web Sockets. It seems as a panacea: tolerant to firewalls and routers, allows cross-domain communication, easy to integrate with HTTP load balancers, accepts binary data exchange, works on secure connections and so on. Besides, API of Web Sockets looks as a simple one:
ws = new WebSocket("ws://site.com/demo");
// Callbacks
// Invoked when the connection is created
ws.onopen = function() { alert("Connection opened...") };
// Invoked when the connection is closed
ws.onclose = function() { alert("Connection closed...") };
// Invoked when the browser receives any data by the channel
ws.onmessage = function(e) { console.log(e.data); };
// Sends a message in the channel
ws.send('message')
Is that all, the solution is found? Unfortunately it is not so easy. At the moment only Google Chrome supports Web Sockets (since 4.0.249.0 version). What about user of other browsers? We need some sort of facade on the client side of our application, which uses native interface when Web Socket support detected and some of COMET tricks when it’s otherwise. Looking for the patch on the case Web Socket is unavailable it makes sense to study offers of Kaazing Websocket Gateway. Another one is Orbited in a bound with io.js. Here is support of Websockets is an options among others such as amqp, imap, irc, ldap, smtp, ssh, stomp, telnet, xmpp. Thought they use Python on the server side, which proxies any of communications.
Apparently the most popular solution for now is node.js, but to introduce you into Web Sockets I picked the simplest one WebSocket.js. That’s a tiny JS-library and bridge as Flash-object.
Let’s try to make a test-stand. Having the JS-library, we still need Web Socket server. I took Jetty , which supports Web Sockets since 7.0.1 version. Its status is still – almost stable, but for the test-stand it’s ok. Though, if your backed is written fully on PHP, you can try phpwebsocket or Phpwebsockets . But I must forewarn you of the fact - both of them are experimental.
I’m sure Jetty installation will call no questions from your side, though you can encounter a problem setting up WebSocket.js because of , so called, cross-domain policy by Adobe (as you remember, Websocket,js uses Flash as a bridge). You have to permit to the Flash of opening socket on the server. As for me, the simplest solution is to launch a micro-server on the 843 port, which responds to the policy request with corresponding XML as it is described in the article. Besides, you can find there in the article also example of a simple Perl-server, which can be copied and launched on your server. However, I didn’t like this one and made my own based on this example devzone.zend.com/article/1086.
By default you will get broadcasting. When you send anything through WebSocket all the clients receive the message. You can open two browsers (e.g. Firefox and Chrome – one will work through the bridge and another via Web sockets) and sending a message (channel.send) you will invoke onmessage event handler in both of browsers. What can we get of it? By the way, enough to implement a chat of Google Wave fashion, which shows participants each ones typing in real time. Just define within sending data list addressee ids and check in onmessage handler whether the incoming message is to be accepted or rejected.
var clientID = 1;
ws.send({
senderID: clientID,
receivers: [2,3,4],
payload: {
message: 'a message'
}
});
ws.onmessage = function(e) {
if (clientID in e.data.receivers) {
output.append(e.data.payload.message);
}
};
But going further, it gets clear there must be a possibility to fire events from the server side. If, for example, a new user comes to the side, server is supposed to fire event to let the client side know the user online list should be updated. In fact there can be various events from different sources for the different targets and it ought to be a reliable system to dispatch all that messaging. Here comes on mind simple, but elegant protocol – STOMP. It consists of a few command only (SEND, SUBSCRIBE, UNSUBSCRIBE, BEGIN, COMMIT, ABORT, ACK, DISCONNECT) which are used for STOMP clients and STOMP brokers communication. Particularly Zend Queue has STOMP adapter. Message broker can be built on Apache ActiveMQ or RabbitMQ .
Another approach is use of AMQP protocol. Jetty is a container of JBOSS, so we need some another container as AMQP broker. It can be ZeroMQ or Qpid .
So, I wish you to try Web Sockets, see the new perspectives it opens to make new amazing web-applications, rapid and alive as can be any of desktop ones.