Jean-Francois Arcand works for Ning.com. Previously he has worked for Sun Microsystems where he created Grizzly (NIO Framework) , Atmosphere and was a significant contributor to the GlassFish Application Server. Jean-Francois is a DZone MVB and is not an employee of DZone and has posted 23 posts at DZone. You can read more from them at their website. View Full User Profile

Tricks and Tips With Comet Part 1: Making All Browsers Work Properly

08.27.2009
| 5247 views |
  • submit to reddit

Writing Comet applications is more and more easy, thanks to frameworks like LIft and Atmosphere. On the Client side, the difference between Safari, Opera, Firefox, IE and Chrome can make your application completely unresponsive or broken. Of course, there are some tricks to make it work.

First, if you are new to Comet, I recommend you take a look at this introduction. For this serie, I will use my new project called Atmosphere, which is a framework for writing portable Comet and REST applications. I always use Firefox for developping, and recently I've got surprise when I 've realized all Atmosphere's sample did work on WebKit (Chrome, Safari) and Opera.

First, to make Safari works properly with the Comet technique called http streaming or forever frame, make sure, on the server side, you set the content-type properly and disable the cache.

res.setContentType("text/html");
res.addHeader("Cache-Control", "private");
res.addHeader("Pragma", "no-cache");

That works well with GlassFish and Jetty...but not Tomcat. Why? Because both Jetty and GlassFish append the charset for you all the time, and Tomcat don't. Safari seems to not like it. So the proper code consist of:

       

res.setContentType("text/html;charset=ISO-8859-1");
res.addHeader("Cache-Control", "private");
res.addHeader("Pragma", "no-cache");

Note that Firefox will work without the above, same for IE. Now the above will make the Comet technique called Long-polling working, but http streaming will still be broken on Safari. Why? Because when you suspend the response, if you don't fill out Safari with some data (~2k), all events that will happen once the response has been suspended will be written by the server, but never read/displayed in Safari, Chrome, IE and Opera.  As an example, I always output the following junk before I suspend a response in Atmosphere:

private final static String JUNK = "<!-- Comet is a programming technique that enables web " +
"servers to send data to the client without having any need " +
"for the client to request it. -->\n";

......

for (int i =0; i< 10; i++){
res.getWriter().write(JUNK);
}
res.getWriter().flush();  

If you are using Atmosphere REST module using Scala, you also need to do something like:

var JUNK : String = "<!-- Comet is a programming technique that enables web " +
"servers to send data to the client without having any need " +
"for the client to request it. -->\n"

@Suspend
@GET
@Produces(Array("text/html;charset=ISO-8859-1"))
def suspend() = {
var s = new StringBuilder()
for (i <- 0 to 10){
s.append(JUNK)
}
s.toString()
}

Quite painful but until websocket are widely adopted (will they?), you will need a little bit of hacking. But once you know them, that should be easy. Client library like JQuery and Dojo's Cometd implementation already do that for you, but if are using pure javascript (or iframe for the http streaming support), make sure you recall that simple tip. You can download many Comet samples from here. They work on any Java WebServer.

If you have any questions, post them on users@atmosphere.dev.java.net, use Nabble or or tweet them.

Published at DZone with permission of Jean-Francois Arcand, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Rigel Kentaurus replied on Thu, 2009/08/27 - 11:36am

We are full of ugly patches, and now, enter COMET, the ugliest of all ugly patches I have seen lately.

When I read in a JSF framework that they'll have PUSH support I immediately yelled "how?" and then when I came to read about the implementation I was deeply dissapointed. Having a thread per user, hogging resources in the server, no true socket implementation, dealing with timeouts, error conditions, restarting the HTTP request, syncronizing the session if restarted. It's all so ugly I don't like thinking about it.

Even if it is abstracted into a higher level framework, I don't care. It's like building a house over mud and using sticks. I don't care if the walls are premade for me.

Even so, I'd probably end up using some "COMET" for a project. After all, it's better than the AJAX polling that we used to do. But it's the same resource intensive (on the server) problem, and a lot of patches. If I have the option, and the client-policies-everything permits, I'd rather program a real client-server application delivered by java web start instead of all th is HTTP hacking.

 

 

Jose Maria Arranz replied on Thu, 2009/08/27 - 1:07pm

IMHO http streaming is ahead of the current state of browser market (with many IE 6 all around and many mobile browsers).

I'm not confident with http streaming so I prefer long-polling, it works in ANY AJAX capable browser including mobile ones, of course http streaming would be better but today is not an option if you want to use Comet in any browser and long polling hasn't buffering problems.

 

Jose Maria Arranz replied on Thu, 2009/08/27 - 1:14pm in response to: Rigel Kentaurus

@Rigel Kentaurus: But it's the same resource intensive (on the server) problem

Yeah right, but Comet gives you REAL TIME capabilities to your web site/application, if you don't need real time or a simple AJAX polling is enough don't use Comet. Comet is not a new hype or fashion, is the solution for a problem: unattended and automatic changes on the web site in real time.

 

Rigel Kentaurus replied on Thu, 2009/08/27 - 3:17pm

I agree with that, it gives real time capabilities to the application, a sample COMET chat that I tested was by far more responsive than the one that used classic AJAX polling.

However, even if it is a solution, that wouldn't mean it is the correct solution, it is currently too costly to implement on the server in terms of memory (holding several http heavy processes), for a good implementation major changes would have to be made to both the server and the applications. The container of your choice wouldn't stand more than 150 concurrent connections (either websphere, BEA, etc), on pretty decent hardware. And that's just for one thread holding a response, I don't want to see what will happen when several people start rolling their components "Comet powered", and then do a mashup of those, 6-8 threads per page load, 10 clients load the page.. that's it, my server is maxed out

It is a nice lab experiment, and it might be a solution, but IMO it is a bad one. I'm not suggesting AJAX polling either, as that is equally intensive. I think I'd have to accept that for reaching that level of interaction and real-time response I'm better of with a real client-server, applet, or standalone application.

Jose Maria Arranz replied on Fri, 2009/08/28 - 2:51am

Threads are really cheap and memory is a bargain these days. The problem is not the number of threads, is "what these threads are doing".

Comet means (almost) instantaneous notification of events in the server to the registered clients. If your Comet based application does not generate many "Comet events" your thousands of threads will be sleeping most of the time and the CPU will be bored. On the contrary the Comet application monitoring a big stock market will be overloaded delivering notifications to two or three clients. This situation does not fully change by using other non-web solutions; of course a pure socket based solution will be more effective than HTTP and long polling.

This is the perspective of a "thread intensive" Comet application, another approach is a NIO based (the kind of Comet that Grizzly can provide too), in this case a small number or threads are used to dispatch Comet events sequentially to your clients. In essence is not very different to the "thread intensive" version because the thread dispatcher of the S.O. kernel is using the very small number of real CPU threads.

Again in a NIO case if your Comet application sparingly generates events your NIO threads will be bored most of the time, independent of the number of clients.

In summary, any average computer can manage thousands of threads, thousands of sockets, thousands of pieces of memory associated to clients with no problem, the number of clients is not the only problem. The number (frequency) of Comet events and how much CPU power/time we need by Comet event and client are very important too, more events, more clients and more time per event is more CPU used.

Time to deliver a Comet event = time_generate_event + time_per_client_per_event * n_clients

Time to deliver N Comet events = n_events * (time_generate_event + time_per_client_per_event * n_clients)

"Time_generate_event" is the computing cost of the Comet event independent of clients. This cost can include specific business related taks (update a database etc).

"Time_per_client_per_event" is the computing cost to deliver the Comet event to the client. This is not only "Comet related" tasks, may include a database updating of user data etc.

As you can see if time_generate_event is almost zero and time_per_client_per_event is almost zero (both are the answer to "what is doing the thread") the CPU use can be low.

If the "Time to deliver a Comet event" is greater than the time between Comet events, you are in trouble (I'm excluding if the delay between the Comet event generation and server response from end user perspective is acceptable).

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.