An Overview of Zlib Compression into VNC 3.3.3

I wanted to add Zlib compression to VNC 3.3.3, but I didn't want to make it a special encoding, as was done in a previous implementation of Zlib for VNC. Instead I took the following approach:

Protocol Change

Obviously the best place to add a request for zlib compression would be in the client and server initialisation messages. However, this would change the size of the messages, and require a bump in the protocol number.

For now, I've chosen to have the client send a message immediately after the receipt of the server initialisation message. This is:

#define rfbClientWantsZlibs 10, which is a 2 octet message. The second octet in the message holds the level of zlib compression desired. Values 1 to 9 are legal, other values are illegal, and the server can choose to do anything with these illegal values like ignore them.

If the server supports zlib compression, it immediately returns a message:

#define rfbServerZlibsOn 10, which is just the one octet. Once this single octet message is sent, all further server -> client data is zlib compressed.

The main shortcoming in the new protocol is: if a client asks for zlib compression to a server which doesn't support it, the server closes the connection because it cannot understand client message #10.

Server Zlib Implementation

This section refers to the patches to the VNC server for X11, version 3.3.3. Where required (i.e for messages after the server initialision message), calls to WriteExact() are replaced with ZWriteExact(), which performs the same functionality as WriteExact() but compresses the data stream. Each client data structure has fields:
    z_streamp Zstream;          /* Pointer to data structure used for */
                                /* zlib compression of server output */
    Bool useCompression;        /* If true, do compression in ZWriteExact */

Client Zlib Implementation

This section refers to the patches to the VNC client for X11, version 3.3.3. The client has a global variable:
    Bool usingCompression;	/* If true, server has turned compression on */
and a new AppData field:
    int zlibCompression;	/* Holds the level of zlib compression */
The read() call in ReadFromRFBServer() now calls Zread(), which performs exactly the same task as read(), but uncompresses the server's data stream if required.

Results from using Zlib Compression

Over a 33.6Kbps modem connection from a Unix client to a Unix server, with a zlib level of 9 (i.e vncviewer -zlib 9 remote:1), I find that zlib compresses the server's data stream by between 2.0 and 3.0. This has a significant speed improvement over this slow link.

On a localhost connection with a zlib level of 9, I get a subjective latency of less than 100ms when compared with no zlib compression. I can't guess the latencies over the 33.6K link; the link's latencies overwhelm the compression's latencies.


Warren Toomey, wkt@tuhs.org, 9th November 1999