Skip to main content

Implement a real-time server push in Ajax applications using socket-based RIA technologies

Sandeep Malik photo
Sandeep Malik is a Tech Lead for IBM Cognos NOW! and works out of India Software Labs, Pune. He has been involved in the design and architecture phase of new generation UI for the Cognos NOW!, and in memory and real-time streaming OBI (Operation Business Intelligence) engine. Sandeep has extensive experience in heavy duty graphics, charting libraries, client-side streaming, non-blocking I/Os, and in general, asynchronous systems. Prior to IBM, Sandeep worked in a network security domain, analyzing the patterns that change the network traffic distribution (for example, botnets, worm scans, and so on). He has also worked on implementing Servlets 2.4 spec in one of his previous companies. During his free time, he enjoys watching cricket and wishes that in his next life he could become a cricketer, too!

Summary:  The new range of advanced user interface (UI) applications requires some aspect of the "server-push" feature so clients can be notified immediately of any server-side changes. Unfortunately, the HTTP spec does not address the issue of any server-side initiated communication, so the server-push has traditionally been implemented through client-side polling. This technique tends to generate a lot of unnecessary traffic and non-optimized applications. Thankfully, certain Rich Internet Application (RIA) technologies do allow the opening of a dedicated socket channel, with the back-end server providing an opportunity for Asynchronous JavaScript and XML (Ajax) applications to piggyback on their APIs and implement a server push. This article explores this technique in a variety of ways, and helps you understand it well enough to begin your own implementation.

Date:  22 Sep 2009
Level:  Introductory PDF:  A4 and Letter (37KB | 11 pages)Get Adobe® Reader®
Activity:  5510 views

Introduction

Ajax technology has been around for quite some time now, and the development momentum has really started to pick up. More and more Web sites are being designed with Ajax in mind, and developers have started to push Ajax to its limits. With the advent of phenomena like social networking and collaborative reporting, a whole new set of demands has started to appear. Users like to be notified if any other user has made changes to any activity being watched. Or, if a Web site displays dynamic data, such as stock market prices, then all the users must be notified about the changes instantly.

These scenarios lend themselves to a general class of problem called "Server Push." Typically, the server is the central entity, which gets notified first of any changes that happen, and it's the server's responsibility to notify all of the connected clients about the changes. Unfortunately, HTTP is the defacto standard protocol for client-server communication, and it is a stateless and, in a sense, unidirectional protocol. All the communications in an HTTP scenario must be originated by a client and ended by the server, whereas the scenario that I am explaining requires the reverse. For a server push, I want the server to start the communication and send the data to the client. The HTTP protocol has no provision for this, and Web site application developers use ingenious ways to circumvent these problems, such as polling, where a client keeps contacting the server at a fixed (or configurable) interval of time to find if any new updates are available. Most of the time, these polls will be wasteful because the server will not have any updates. This does not come for free, and there are two problems associated with this approach.

  1. It's a huge waste of network resources. Each poll request typically creates a TCP socket connection (unless HTTP 1.1 has its keepAlive setting as true, in which case a previously created socket is reused). The socket connection itself is expensive. On the top of that, each request carries some data over the network; if the request does not find any updates on the server, this data transfer is a waste. If there are other applications running on the client machine, these polls decrease the bandwidth available to transfer data.
  2. Even if a request is successful and does bring an update back to the client, depending on the polling frequency, it may not be real-time. For example, let's say polling is configured to occur every 20 seconds, and just after a request is returned from the server an update happens. This update will not reach the client until the next request comes again in 20 seconds. Therefore, the updates that are present on the server, ready to be consumed by clients, have to wait for some time before that can happen. This wait could be unacceptable for applications that need to run as close as possible to real time.

Given these two problems, polling may not be an appropriate approach for enterprise applications requiring critical, real-time, server-side updates. In this article, I discuss various approaches that can be alternatives to polling. Each alternative works better in some scenarios than others. I'll explain these scenarios, as well as show a set of UIs where a real-time server push is required.


Server update techniques in Ajax applications

Let's look in some detail at common techniques used to update information from the server, which simulates a server push.

Short poll

Short poll, or frequent poll, is just what I discussed in the beginning of this article. This approach may work best in the cases where:

  1. Enough bandwidth is available.
  2. Statistically, most of the time, requests find updates. For example, stock market data will generally always have an available update.
  3. HTTP 1.1 protocol is used. Therefore, the same socket connection is kept alive and re-used with the keepAlive=true setting.

Long poll

Long poll is another approach that is used to update server data. The idea here is that a client establishes the connection, the server holds back the connection (by making the request thread wait on some condition), and when the data is available the server sends the data through the held connection and then closes the connection. The client, upon receiving the updates, immediately re-establishes the connection, and the server repeats the process again. This way, the client and server ensure that one request is always pending, and an almost real-time communication is achieved. However, long poll suffers from the following disadvantages:

  1. Browsers generally allow 2 connections per server by default. In this scenario, one connection is always busy. Therefore, the UI is left with only one connection (that is, half the strength) to service user requests. This may cause performance delays for certain operations.
  2. Opening and closing of HTTP connections is still required, which may be expensive in the case of non-persistent connection mode ( keepAlive=false).
  3. It is almost real time, but not exactly real time. (Of course, you can never control external factors like network latency, which will always be present in any approach.)

Streaming channel

Streaming channel is almost the same as long poll; the difference being that the server does not close the response stream. Rather, it intentionally keeps it open, giving an illusion to the browser that more data is yet to come. However, streaming channel has its own disadvantages:

  1. The biggest issue here is flushing. Traditionally, Web servers cache the response data and only send it after a sufficient number of bytes or chunk has been received. In this case, even if the application flushes the data, it may still be buffered by the server for optimization. Worse still, if there's a proxy server sitting between a client and server, then the proxy can buffer the data further for its own convenience.
  2. Some browser implementations may decide to close the socket on their own if they find it to be open for a longer duration. In such a case, the channel needs to be re-established.

Generally, the first issue is circumvented by attaching a garbage payload with every streamed response so that the response data is enough to fill the buffers. The second issue is circumvented by sending a "keep-alive" or "sync" message at constant intervals to fool the browser into thinking that data is coming at a slower rate.

Each of these solutions has their niche use cases. All of them have been used in some solutions over the Internet. However, they all suffer from the same problem: They lack scalability. Typically, to hold back a request, you need to hold back the thread processing the request because almost all of the application servers today perform blocking I/O. Even if they don't, Java™ 2 Platform, Enterprise Edition (J2EE) provides no standards to perform non-blocking I/O for the HTTP request and response. (With Servlets 3.0 APIs, this problem should be resolved as these APIs include Comet Servlets.)

What you need as of now is a non-blocking I/O (NIO) server sitting at the back, and client applications connecting through that. Because such a socket will be a pure TCP binary socket, it will achieve the following objectives:

  1. Because of NIO on the server side, much better scalability can be achieved.
  2. There are no issues of response buffering because this socket is under direct control of application.

Having said that, it is imperative to note four drawbacks to this approach:

  1. Because this is a binary TCP socket, the application cannot really make use of SSL security provided by the HTTPS layer. So, applications requiring data security may need to provide their own encryption facilities.
  2. Generally, the server socket will be run on a port different from 80, so there will be issues with firewalls that allow traffic only from port 80. Therefore, some port configuration may need to be done.
  3. Ajax clients cannot really open a TCP socket connection with the back end.
  4. Even if Ajax clients could perform an open function, they cannot understand binary content, as Ajax is for XML or JSON (text-based) formats.

What I am highlighting in this article is how you can actually circumvent the third and fourth issues. If you are okay with security and firewall issues, the rest of the issues can be dealt with. The benefits of doing so are enormous.

You achieve the maximum possible real-time (barring the external factors like network latency, and so on) server push behavior for your applications, and you achieve a pretty scalable solution in terms of the number of simultaneously connected clients.

Now, lets start exploring how you can address issues 3 and 4 from above.


Socket-based RIA technologies

Ajax cannot really resolve issues 3 and 4. Therefore, you need to get solutions using other RIA technologies. There are two RIA technologies that offer socket APIs that can interact with Ajax applications as well. These are Adobe Flex and OpenLaszlo. Fully introducing these technologies is really out of the scope of this article (see Resources for more information), but two features that these technologies provide are:

  1. Both are capable of opening a TCP binary socket with the back end
  2. Both can interact very well with Ajax applications (basically JavaScript) running in the same browser window

However, this only partially addresses your concerns. Yes, you can now open a socket, and, yes, you can now make Ajax applications use them, but Ajax applications still cannot deal with pure binary data. What about that? Well, it turns out that both of these technologies do offer a variant of the binary TCP socket called XMLSocket, which can be used to transfer pure XML data back and forth. That's exactly what you need. If these technologies could open a socket with the server and if they can transfer XML data, you're done. Ajax applications can make full use of that to simulate a real-time server-push feature. Take a look at how you would do that.

Implementing an Ajax server push

I'll explain this technique using two different tools: Adobe Flex and OpenLaszlo. First of all, you need to write a back-end server that can accept connections and cache them. You don't want to stray too far from the theme here, so keep the server blocking I/O-based.

You need to create a server socket that can accept connections at a predefined address:


Listing 1. Creating the server socket
public class SimpleServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(new InetSocketAddress("localhost",20340));
        Socket socket = serverSocket.accept();
    }
}

Here, I've bound the server socket at the localhost:20340 address. When a client connects to the server socket, it will give me a socket representing that connection. Flex clients will then ask for a policy file that is part of their security model. Typically, this policy file will look like Listing 2.


Listing 2. Flex client policy file
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM 
    "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy> 
<allow-access-from domain="*" to-ports="20340"/> 
</cross-domain-policy>         

Immediately after connecting, the Flex client will send a request for the policy file. The request will contain just one XML tag: <policy-file-request/>. In the response, you need to return this policy file. The code in Listing 3 does just that.


Listing 3. Send policy file response
public static void main(String[] args) throws IOException {
   ServerSocket serverSocket = new ServerSocket();
   serverSocket.bind(new InetSocketAddress("localhost", 20340));
   Socket socket = serverSocket.accept();
   String POLICY_REQUEST = "<policy-file-request/>\u0000";
   String POLICY_FILE = "<?xml version=\"1.0\"?>\n" +
      "<!DOCTYPE cross-domain-policy SYSTEM 
         \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" +
      "<cross-domain-policy> \n" +
      " <allow-access-from domain=\"*\" to-ports=\"20340\"/> \n" +
      "</cross-domain-policy>";
   byte[] b = new byte[POLICY_REQUEST.length()];
   DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
   dataInputStream.readFully(b);
   String request = new String(b);
   if (POLICY_REQUEST.equals(request)) {
       DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
       dataOutputStream.write(POLICY_FILE.getBytes());
       dataOutputStream.flush();
       dataOutputStream.close();
   } else throw new IllegalArgumentException("unknown request format " + request);
 }         

This establishes a successful connection with the client. Now, the server can start a "handshake" kind of protocol with the client, in which it will typically assign a unique ID and send it to the client. After that, the server can cache the socket against the ID, and, at any time after that, if the server needs to push some data to the client, it can locate the socket by the ID and use its output stream. Fortunately, OpenLaszlo also uses the same policy-file-based mechanism and, hence, the same server code can work for both scenarios.

Now take a look at how you can create a Flex socket and then connect with Ajax applications.

Using Adobe Flex to open a client socket

The code in Listing 4 shows how you can open a client socket from Flex:


Listing 4. Open a client from Flex
var socket : XMLSocket = new XMLSocket();
// register events:
socket.addEventListener(Event.CLOSE, closehandler);
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.OPEN, openHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, readHandler);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
socket.connect("localhost",20340);         

After the call to socket.connect() is made, Flex sends a request to the server for the policy file and expects an XML response. When that's complete, the connection is established, and this socket can now be used to push data from the server.

As the final piece in the puzzle, you will see how Flex can call Ajax as an application. For this, you write a generic JavaSscript function that can handle the server-side messages. Let's call this method handleServerMessageReceived(message). This method gets the XML code from the server, and what this method does with the message is application-specific. The code in Listing 5 shows how Flex can call JavaScript functions. This code is for the readHandler method, which gets called when a server XML message is received.


Listing 5. readhHandler code using handleServerMessageReceived(message)
public  function readHandler(e :  DataEvent) : void {
  var message   : XML = e.data as XML;
  ExternalInterface.call("handleServerMessageReceived", message);
}         

That's all! It's as simple as that. You have created an XML socket connection. When the data arrives from the server, you can call some generic handler function in the Ajax application, which can process those messages. The full source code is available as a download (see Download).

Now, take a look at how OpenLaszlo can achieve the same objective.

Using OpenLaszlo to open a client socket

Because OpenLaszlo applications target both the Flash and DHTML platforms, their APIs and scripting language are somewhat similar to those of Flash and JavaScript. This is mainly for the convenience of Web developers who want to migrate to OpenLaszlo as an alternative for RIA.

OpenLaszlo provides two ways to create a persistent connection with the back end. One way involves using the ConnectionManager APIs provided as part of Lz (Short for Laszlo) standard libraries. However, their documentation clearly specifies the following:

"Warning: This feature is provisional. It works in limited capacity situations and is fine to develop with, but we do not recommend deployment (with the possible exception of low-capacity, non-mission critical deployment) with this feature. Please consult Laszlo Systems directly if you have questions about the robustness of an application that uses this version of the persistent connection."

Maybe it is an experimental technology right now, and in future versions of OpenLaszlo, it will be substantiated further.

The second way is similar to Flex, in which you manually open an XML socket connection and wait for the READ_DATA event to occur. Listing 6 shows how to do this.


Listing 6. Defining the XMLSocket class
<class name="ClientSocket" extends="node">
	<attribute name="host" />
	<attribute name="port" />
	<XMLSocket name='xml_socket'/>
	<handler name="oninit">
		// connect the socket here:
		xml_socket.connect(host,port);
	</handler>
	<handler name='onData' reference='xml_socket' args='messageXML'>
 <![CDATA[
		ExternalInterface.call(‘handleServerMessageReceived',messageXML);
	]]>
	</method>	
</class>         

(Other handlers are omitted for brevity. A complete code listing can be found in the download for this article.)

That's it. Creating a socket object and connecting it is as simple as that. This code listing creates a new class called ClientSocket and then declares an XML socket object named "xml_socket." Whenever this socket object reads data from the server, it will fire an onData event that will be handled by the handler defined for onData. Finally, in the onData handler, you call the external JavaScript function residing in the Ajax application. From there on, the flow remains the same as with the Flex client.

To create an ClientSocket object is as simple as declaring it:


Listing 7. Declaring the ClientSocket
<canvas>
	<ClientSocket id='serverPushSocket' host='localhost' port='20340'/>
</canvas>         

When the init event is fired for ClientSocket, it attempts to connect to the back end at the specified host and port. (See the oninit handler in Listing 6.)


Summary

In this article, I discussed various approaches for simulating a server push, ranging from pure polling to a real-time server push, and noted the strengths and weaknesses of each approach. Finally, I focused on one approach that gives the best results in terms of server scalability and real-time server push behavior.

Server push is not for every application. In fact, most of the applications fair very well in a normal request/response scenario. Others work adequately using polling and the similar techniques. It is only for those real heavyweight applications, where server updates are inevitable and clients need to be notified instantly, that you really need the techniques discussed in this article. It is again noteworthy to mention that this technique still suffers from two major drawbacks:

  1. The client socket cannot make use of SSL encryption facilities if the data needs to be transferred over HTTPS.
  2. Firewalls need to allow a non-standard port (other than 80) for client sockets to connect back to the server.

However, custom encryption routines can easily be written with so many open source libraries available in the market. Similarly, configuring a firewall is also not a big deal and is actually a small price to pay for getting such a strong capability as a real-time server push.



Download

DescriptionNameSizeDownload method
Source codesamples.zip9KBHTTP

Information about download methods


Resources

About the author

Sandeep Malik photo

Sandeep Malik is a Tech Lead for IBM Cognos NOW! and works out of India Software Labs, Pune. He has been involved in the design and architecture phase of new generation UI for the Cognos NOW!, and in memory and real-time streaming OBI (Operation Business Intelligence) engine. Sandeep has extensive experience in heavy duty graphics, charting libraries, client-side streaming, non-blocking I/Os, and in general, asynchronous systems. Prior to IBM, Sandeep worked in a network security domain, analyzing the patterns that change the network traffic distribution (for example, botnets, worm scans, and so on). He has also worked on implementing Servlets 2.4 spec in one of his previous companies. During his free time, he enjoys watching cricket and wishes that in his next life he could become a cricketer, too!

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=430010
ArticleTitle=Implement a real-time server push in Ajax applications using socket-based RIA technologies
publish-date=09222009
author1-email=sandeep.malik@in.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers