Although
Java is being touted as the best way to do animation on the Web,
you can also write CGI programs to produce animation. There are
two mechanisms for creating animation: client pull and server push.
In client pull, a new HTTP connection is opened
every time a document is requested. In server push, however, the
connection is kept open until all the data is received by the client.
That is the main difference between the two mechanisms. As a result,
you can have an animation in an otherwise static document by using
the HTML <IMG> tag to access the CGI program
instead of a URL to an image, as introduced in the "Inserting Multiple
Dynamic Images" section at the beginning of this chapter.
Client pull requires a special directive either in the HTML
document header or as a part of the CGI program's HTTP
response. This directive instructs the client to retrieve a specified
document after a certain amount of time. In other words, the client
opens a new connection to the server for each updated image (see
Figure 6.7).
Server push involves sending packets of data to the client
periodically, as shown in Figure 6.8.
The HTTP connection between the client and the
server is kept open indefinitely. Server push can be implemented
in a CGI program through the use of the multipart/x-mixed-replace MIME
type.
Both client pull and server push are supported only by Netscape
Navigator (version 1.1 and higher) and Internet Explorer.
Here is a simple example of an HTML document
that displays the time continuously:
<META HTTP-EQUIV="Refresh" CONTENT=5>
<!--#echo var="DATE_LOCAL"-->
Animation
depends on updating the browser's window at regular intervals with
new material from the server. Browsers provide a way to update their
windows called refreshing.
In the example shown above, we trick the browser into issuing its
refresh command every five seconds, so that it retrieves the document.
The document simply uses server side includes to display the current
time. (See Chapter 5 for more information
on Server Side Includes.)
The META tag is part of
the HTML 3.0 specification used to simulate HTTP
response headers in HTML documents. In this case,
it is used to simulate the "Refresh:" HTTP header
with a delay of five seconds.
The "Refresh:" header is non-repeating; it does not load the
document repeatedly. However, in this example, "Refresh:" is specified
on each retrieval, creating a continuous display.
Here is an example of a CGI program that performs the same
operation as the previous HTML code:
#!/usr/local/bin/perl
$delay = 5;
$date = "/bin/date";
print "Refresh: ", $delay, "\n";
print "Content-type: text/plain", "\n\n";
print `$date`;
exit(0);
Remember, SSI directives cannot be included in a CGI program.
So, the date command is used to output the
current date and time.
Now, let's look at the directive used to load a different
document after a specified time:
<META HTTP-EQUIV="Refresh" CONTENT="5; URL=https://your.machine/name.html">
This example loads the file specified by the URL after five
seconds. If the file name.html does not contain
another "Refresh:" header, there is no animation, because "Refresh:"
is non-repeating. The corresponding CGI statement would be:
print "Refresh: 5; URL=https://your.machine/name.html", "\n";
As a final example of client pull, here's a CGI program that
loads a document with a random fortune message every ten seconds.
#!/usr/local/bin/perl
$fortune = "/usr/local/bin/fortune";
$refresh_time = 10;
print "Refresh: ", $refresh_time, "\n";
print "Content-type: text/plain", "\n\n";
print "Here is another fortune...", "\n";
print `$fortune`;
exit(0);
This is a repeating document, because a "Refresh:" header
is specified every time the program is executed. The program uses
the UNIX fortune command,
which generates a random fortune each time it is invoked.
Server push
animations can be created using the multipart/x-mixed-replace
MIME type. The "replace" indicates that each
data packet replaces the previous data packet. As a result, you
can make smooth animations. Here is the format in which this MIME
type is used:
Content-type: multipart/x-mixed-replace;boundary=End
--End
Content-type: image/gif
Image #1
--End
Content-type: image/gif
Image #2
--End
Content-type: image/gif
Image #3
--End--
In the first Content-type declaration,
we declare the multipart/x-mixed-replace content
types and establish "End" as the boundary string. We then repeatedly
display new images (declaring new content types of image/gif),
ending each image with the "--End" string. The result is that the
images are displayed one after another.
Let's look at an example that uses the server push mechanism.
#!/usr/local/bin/perl
$| = 1;
$webmaster = "shishir\@bu\.edu";
$boundary_string = "\n" . "--End" . "\n";
$end_of_data = "\n" . "--End--" . "\n";
$delay_time = 1;
First, we define the boundary strings that need to be sent
to the client. We also set the delay time between images--
in this
case, one second.
@image_list = ( "image_1.gif",
"image_2.gif",
"image_3.gif",
"image_4.gif",
"image_5.gif" );
All of the images that will be used in the animation are stored
in the @image_list array. In this simple example,
we use only 5 images.
$browser = $ENV{'HTTP_USER_AGENT'};
if ($browser =~ m#^Mozilla/(1\.[^0]|[2-9])#) {
print "Content-type: multipart/x-mixed-replace;boundary=End", "\n";
The name of the client browser is obtained using the environment
variable HTTP_USER_AGENT. If the browser is Netscape
version 1.1 or higher, the multipart MIME type
is sent to it, along with the initial boundary string. (Netscape
uses "Mozilla" as its user agent string.)
for ($loop=0; $loop < scalar (@image_list); $loop++) {
&open_and_display_GIF ($image_list[$loop]);
print $boundary_string;
sleep ($delay_time);
}
print $end_of_data;
A loop is used to iterate through the image_list
array. Each image is displayed using the open_and_display_GIF
subroutine. A boundary is then sent to the client, and the program
proceeds to sleep for the specified amount of time. It is important
to print the boundary after the image and before
the sleep command to ensure that the server
"pushes" the entire image to the client. The process is repeated
for all the images in the array. Finally, the terminating boundary
string is sent to the client.
} else {
&open_and_display_GIF ($image_list[0]);
}
exit(0);
If the browser is not Netscape version 1.1 or higher, only
the first image stored in the array is displayed.
sub open_and_display_GIF
{
local ($file) = @_;
local ($content_length);
if ( (open (FILE, "<" . $file)) ) {
$content_length = (stat (FILE))[7];
print "Content-type: image/gif", "\n";
print "Content-length: ", $content_length, "\n\n";
print <FILE>;
close (FILE);
} else {
&return_error (500, "File Access Error",
"Cannot open graphic file $file!");
}
}
This routine should be very familiar to you. First, it sends
the image/gif MIME type, along
with the length of the image. Then, the image is printed to standard
output.
One final note: If you are using an NCSA
server, it is better to create the CGI server push animation program
as a non-parsed header ("nph") script, as described in Chapter 3, Output from the Common Gateway Interface. That
way the server will not parse the HTTP headers,
and instead will send the information directly to the client. The
main advantage of this is reduced "jerkiness" in the animation.
Just to refresh your memory, you need to name the script with an
"nph-" prefix, and the first lines that are output from your script
should be:
print "HTTP/1.0 200 OK", "\n";
print "Content-type: multipart/x-mixed-replace;boundary=End", "\n";