Requirements
 
Prerequisite knowledge
A basic understanding of ColdFusion, JavaScript and client-server architecture
 
User level
Intermediate
 
 
Required products
Adobe ColdFusion Enterprise Edition (2016 release) (Download trial)
 
 
Sample files
HTML5 has become popular amongst web developers and revolutionized the way developers write web applications. WebSocket is a core to HTML5 specification and a perfect solution for pushing data from the server to client in real time. Until now, to achieve this process you had to use a traditional HTTP mechanism such as Long Polling, comet, server-side push, or XMLHttpRequest, all of which offered poor performance and did not guarantee up-to-date real-time information—in fact, the development community considered many of these options convoluted hacks.
 
This article provides an overview of HTML5 WebSockets in general, and how you can use them within ColdFusion 10. This article covers how to initiate a WebSocket connection and explains using various JavaScript functions to send and receive messages between client and server.
 
The WebSocket protocol is an advanced technology compared to HTTP when thinking about the design and development of a real-time enterprise web application. WebSockets were introduced as part of the HTML specification as a protocol that enables full, duplex, bi-directional TCP communication over a single socket that sends messages between client and server continuously. The HTML5 WebSocket protocol is a big step toward the future that leaves behind the HTTP request-response paradigm.
 
Normally in HTTP, when your web browser visits a website, the browser sends a request to the remote server. The web server acknowledges this request and returns a response. In many cases, the response (data such as stock prices, news reports, twitter feed, ticket sales, traffic patterns, medical device readings, and so on) might be stale by the time your browser renders the page for the user. If you wanted to get the most up-to-date real-time information, you had to constantly (and manually) refresh that page. This may work for some applications, but it's definitely not the best solution.
 
The HTML5 WebSocket protocol simplifies the process above while also making the development of real-time web applications faster and easier. Using the WebSockets protocol, once you initiate the connection, the server can send multiple responses in tandem without re-initiating or waiting for a browser request. WebSocket, unlike HTTP (where a browser might close a connection once it sends the request and receives the result), maintains a permanent connection and therefore provides better socket management.
 

 
What are WebSockets?

 
The purpose of WebSockets

The HTML5 WebSockets protocol provides a reliable, fast, and high-performing solution that helps you to build a scalable, real-time, event-driven web application. Take advantage of WebSockets to develop modern web application that are more rich, expressive, and dynamic; to build components such as a real-time stock ticker, news reports, feed reader, chat interface, monitoring dashboards, dashboards for other various purposes, on-line games, application-based social networks, and so much more.
 
Technology-wise, the HTML5 WebSockets protocol offers a host of advantages over conventional web communication, as follows:
 
Full duplex communication: WebSocket provides a real-time, full-duplex communication on a single TCP connection—a perfect condition for all real-time server push and streaming services on the internet.
 
Performance: For a real-time, bi-directional communication, WebSocket provides a dramatic improvement over traditional mechanisms. Depending upon the frequency of browser refreshes, you may see an improvement of 100 times or more with HTML5 WebSockets compared to existing HTTP-based solutions.
 
Streamlined communication: Based on the TCP protocol, the WebSocket protocol reduces the protocol overhead for each request/response to a couple of bytes rather than 800 bytes per transaction (as in the case of HTTP).
 
Lesser browser reload: As the server push drives WebSockets, the browser need not reload the main page over and over again.
 
Low network latency: WebSockets reduce unnecessary network traffic and latency to one-third compared to HTTP. Network latency is a parameter that measures the delay typically incurred for a packet of data to get from one designated point to another.
 
As discussed above, there are many advantages for using WebSockets, but performance and low overhead are key success factors. According to Google's Ian Hickson, editor of the HTML5 specification:
 
"Reducing kilobytes of data to 2 bytes…and reducing latency from 150ms to 50ms is far more than marginal. In fact, these two factors alone are enough to make Web Sockets seriously interesting to Google."
 

 
WebSockets support in ColdFusion 10

Before ColdFusion 10, if you wanted to develop a real-time, bi-directional web application, you had to use "long polling," or other server-side push technologies such as comet. You also had to get these libraries, integrate them, and write JavaScript code; and even after performing all of these tasks, you couldn't really guarantee that the application that you built was a true real-time application.
 
Now, because of WebSockets in ColdFusion 10, you don't need to look any further. You just simply need to work with a new ColdFusion tag and its attributes. ColdFusion 10 provides a set of JavaScript functions that you can use to perform various WebSocket tasks, as well as generating some when you use the new CFWEBSOCKET tag. ColdFusion 10 provides this tag and the set of JavaScript functions within an existing CF syntax that you can easily understand and feel comfortable using.
 
Beside making the HTML5 WebSockets core protocol easily available to you, ColdFusion 10 also provides a WebSocket-based messaging framework to publish a message to all subscribed web clients. This messaging layer works on a subscriber/publisher model, where ColdFusion notifies all the clients subscribed to an endpoint (called a "channel") in real-time for any update on the server.
 
 
WebSocket communication modes
 
ColdFusion 10 provides different modes for WebSocket communications, as follows:
Broadcast mode: This WebSocket communication mode follows a subscriber/publisher model where the host includes multiple clients and a server. First, a client subscribes to a channel. Once subscribed, the client receives a message from the server whenever the server publishes a message. ColdFusion 10 supports the following different ways for publishing a message:
 
  • From the client side as is: The client sends a message to the server and the server broadcasts the message as is.
     
  • From the client with some server-side processing: The client sends a raw message to the server and the server processes the message (in a CFC) before broadcasting it. (See the invokeAndPublish JavaScript function for more details.)
  • From the server: The server initiates a message to the client, without client involvement. (See server-side publish through the WSPublish function.)
Point-to-Point(P2P) mode: This WebSocket communication mode provides bi-directional communication between a specific client and the server. This is a simple, channel-less communication where a client need not subscribe to a channel; rather, a client can make a plain request to server to execute a ColdFusion template.
 
 
Configuring WebSockets
To implement the broadcast- based messaging layer in ColdFusion, you specify the channel details in Application.cfc, use the new tag CFWEBSOCKET to create a WebSocket connection and then send, receive, and manage the connection through various JavaScript functions.
 
You must specify the communication channel(s) in Application.cfc for communication to occur between publisher and subscriber. Add the following line in your Application.cfc file:
 
this.name = "WebSocketDemo"; this.wschannels = [{name="stocks"},{name="chat"}];
By adding this line, you have registered stocks and chat communication channels. As I have done here, you can specify multiple channels; you simply specify individual channel entries as a struct. Once you register a channel, you can specify a subchannel for it (such as stocks.technology , chat.usa.ca ) at runtime without registering it in Application.cfc.
 
 
Creating WebSockets
You use the cfwebsocket tag to initiate the webSocket connection. Specify the name attribute to direct the WebSocket object to perform various tasks within JavaScript.
 
<cfwebsocket name='webSocketObj'onMessage='messageHandler' onError='errorHandler'onOpen='openHandler'subscribeTo='stocks,chat'/>
This code establishs a connection with the WebSocket server. The server responds with a welcome message that notifies the publisher or subscriber that the connection was established. This welcome message is received in user-defined openHandler callback functions. As you can see, you can specify various handlers for different purposes. The client uses the onMessage handler to receive an incoming message from the server. Similarly, the client uses the onError handler to intercept an error if there is one on the server side.
 
Though the server provides a JavaScript function for subscribing to a WebSocket channel, you can use the subscribeTo attribute in the CFWEBSOCKET tag to subscribe automatically to channel(s) at the time of creating the connection. The code snippet above subscribes the client to the stocks and chat channels by proving a comma-separated list of channel names.
 

 
Using the WebSocket JavaScript functions

Once you have established a connection with the server, you use the WebSocket object to manage the connection and perform various tasks such as subscribe , publish , unsubscribe , invokeAndPublish , getSubscriberCount . See the ColdFusion Help documentation for a complete list of WebSocket-related functions.
 
 
The subscribe function
Instead of specifying the channels to subscribe to in the subscribeTo attribute of the CFWEBSOCKET tag, you can use the JavaScript function subscribe to subscribe to a channel. Unlike subscribeTo attribute, with the JavaScript subscribe function, you can specify the channel name to subscribe to, as well as pass additional information for more granular control of your application. The subscribe function optionally takes two arguments: subscriberInfo and messageHandler . The SubscriberInfo argument specifies a set of properties as a JavaScript object that the function passes to the server. Later, on the server side, you can use this subscriberInfo to perform authentication and message filtering programattically.(I will explain this further later in this article). Specify the messagehandler callback function to receive an incoming message from this channel rather than using the messageHandler attribute specified at the tag level. This argument come in handy if the same client needs to subscribe to multiple channels and you want to process the incoming message differently for different channels. See an example in the following code snippet:
 
webSocketObj.subscribe("stocks"); webSocketObj.subscribe("stocks", {age: 25, scriptName:'adobe', minPrice:34});
In this code sample, other than channel name, the code specifies three additional properties: age of subscriber, scriptName , and minPrice , and sends these properties to the server to perform an extra task.
 
 
The unsubscribe function
Use the unsubscribe function to unsubscribe from a channel. Once a user unsubscribes from the channel, the server no longer delivers the messages from the channel to the client.
 
webSocketObj.unsubscribe("stocks");
 
The publish method
The publisher can send the data through a channel using the publish method. First, the server acknowledges the publish request by sending an acknowledge to the publisher and later sends the message to all the subscribed clients for that channel. This function optionally takes an additional argument: the publisherInfo argument. Just like the subscriberInfo argument, the publisherInfo argument is a set of properties sent as a JavaScript object, as follows:
 
webSocketObj.publish("stocks", "message_to_be_published"); webSocketObj.publish("stocks", "message_to_be_published", {publishedBy: 'publisherName', city:'SFO'});
In the second case, along with channel name and message, this code snippet specifies two additional properties publishedBy and city which the channel sends to the server.
 
 
The invokeAndPublish function
Many a times a user may need to invoke a specified method of CFC to generate the message necessary for publishing. Use this function when you only have the raw data with you and you need to process it to generate a message. For example, if you are building a bidding application, you must validate a bidder's new bid before storing its details to the database and before notifying the other subscribed users with the latest bid amount. To invoke this function, specify the channel name, CFC Name, function name, and function argument if applicable. You can specify an optional parameter publisherInfo , similar to the publish function.
 
webSocketObj.invokeAndPublish("stocks", "stockCFC" 'generateData'); webSocketObj.invokeAndPublish("stocks", "stockCFC" 'verifyData', [arg1, arg2, arg3], {bidBy:'bidderName'});
In the second line of code, along with the CFC and the method name, you also pass function arguments and make them available to the verifyData UDF function, which verifies the accuracy of the data.
 
 
Connection management functions
The ColdFusion 10 WebSocket framework provides a set of Javascript function to manage the WebSocket connection, as follows:
 
webSocketObj.isConnectionOpen(); webSocketObj.closeConnection(); webSocketObj.openConnection();

 
Using server-side callback functions: The CFCListener component

The ColdFusion 10 Websocket framework provides server-side callbacks for relevant JavaScript functions to check whether a client has the permission to subscribe/publish to a channel. You can use this callback function to perform data pre-processing or formating before publishing it. ColdFusion 10 provides these callbacks with the CFC component CFCListener . Though using the CFCListener component is optional, you may find its functions handy as you build real-time applications; it can help you control and manage an application's business logic and bring it to the next level.
 
The CFCListener component
 
The CFCListener component is a simple CFC that extends the framework provided by the base CFC, CFIDE.websocket.ChannelListener . This base CFC is the default implementation for all callback functions such as allowSubscribe , allowPublish , afterUnsubscribe , beforePublish , and few more. Based on your application's requirements, you might override the default implementation of these functions. If so, you'll need to register this Listener CFC at the same time you register a channel in Application.cfc. Let's revisit the channel registration code in Application.cfc, as follows:
 
this.name = "WebSocketDemo"; this.wschannels = [{name="stocks", cfclistener= 'stockChannelListener'},{name="chat"}];
This code specifies an additional property cfclistener and registers the stocks channel. The cfclistener property refers to a CFC and overrides the allowSubscribe function of the base CFC. See the code below for stockChannelListener.cfc.
 
stockChannelListener.cfc component extends="CFIDE.websocket.ChannelListener" { public any function allowSubscribe(Struct subscriberInfo) { // overwrite this function to check for permissoin. if(subscriberInfo.age > 18) return true; // Grant permission to subscribe else return false; // Deny permission to subscribe } }
 
CFCListener functions
The following describes the functions in the CFCListener component.
 
 
Susbcribe process functions
The allowSubscribe function: When a web clients initiate a subscribe process by invoking the corresponding JavaScript function, the server receives a request to subscribe the client to that specific channel. In such a case, the server calls the allowSubscribe callback function before actually subscribing this client to the specified channel.
 
public any function allowSubscribe(Struct subscriberInfo) { // overwrite this function to check for permissoin. if(subscriberInfo.age > 18) return true; // Grant permission to subscribe else return false; // Deny permission to subscribe }
This code snippet only allow a person older than 18 years to subscribe to the channel; if the user is under 18 years of age, the function returns a false value. The server invokes this callback function with the struct subscriberInfo , which holds all of the properties that the JavaScript subscribe function passes. Now, revisit the subscribe function and all the properties within it, such as scriptname , age , minPrice ; these properties are also available to this struct. See the complete workflow of the allowSubscribe function below (Figure 1).
 
The complete workflow of the allowSubscribe function

Figure 1. The complete workflow of the allowSubscribe function
 
Publish process functions
The allowPublish function: The server invokes this callback function to check whether the publisher has the permission to publish a message.
 
public any function allowPublish(Struct publisherInfo) { //A person from SFO only can publish. if(publisherInfo.city eq 'SFO') return true; // Grant permission to publish else return false; // Deny permission to publish }
This code only allows a person from San Francisco to publish a message. The code passes a struct called publisherInfo as the only argument for this function, which holds all of the properties passed in the publish JavaScipt function and in the connectionInfo .
 
The beforePublish function: Use this function to perform a database call, business logic, and formatting of a message data before publishing it. You must add the relevant logic based on what your application needs, otherwise it's an empty method; in other words, this function does not do anything by default—you must specify its use.
 
public any function beforePublish(any message, Struct publisherInfo) { //Adding published time information to the message object. //If the message is struct then add the time information as a key // otherwise append it as string. if(isStruct(message) message.publishedAt = now(); else message = message+"publihsedAt:" +now();// String append. }
The canSendMessage function: The server calls this function for each subscribed user for selective publishing, to ascertain whether a particular client is interested in receiving this message or not. You can write the conditional logic based on the passed parameter , message , subscriberInfo , and publiserInfo .
 
public any function canSendMessage(any message, Struct subscriberInfo, Struct publisherInfo) { // This perticular subscriber is interested in knowing the // price of adobe stock only. If its non Adobe stock, he // should not be sent the message. If(message.scriptName eq 'adobe') return true; else return false; }
See a complete workflow of the publish request below (Figure 2).
 
Complete workflow of the publish request
 
Figure 2. Complete workflow of the publish request

 
Using server-side publish: An additional way to publish a message

Until now I have described how to publish a message from the client side using JavaScript. But ColdFusion also provides an aditional mechanism where you can trigger a message publish from the server without any input from client. Use the CFML function wsPublish to publish data from the server side. This function comes in handy when the ColdFusion server receives some notification from an external source, such as an eventGateWay or twitter feed—and then needs to broadcast the notification.
 
<cfset wsPublish("publishdemochannel","Welcome to publishdemo")/>

 
Using Point-to-Point (P2P) communication

Let's assume that you don't need to send the message to multiple clients, rather you need to talk to the server only. That is, let's say that you want a bi-directional communication between one client and one server. The server must respond to each client request (as with HTTP), or ideally the server keeps on sending the response once a client triggers a request (a streaming response as in P2P communication). This kind of communication can be very useful for building a dashboard application, online game application, for single-user and similar uses where a client needs fast and continuous communication with server. To do so, use the JavaScript function invoke for P2P communication. Specify the CFC name and method name that you wish to invoke. Optionally, you can also pass the list of function arguments if your CFC method requires you to pass additional arguments.
 
wsConnection.invoke('myCFC', 'retrieveData'); wsConnection.invoke('myCFC', 'startStats, [arg1, arg2]);
The above code does not specify a channel name because this is a simple channel-less communication. This function is a better and more scalable function than the CFAjaxProxy function, which is an alternative option that will produce the same results.
 

 
Where to go from here

In this article, I have provided a basic overview of the WebSocket protocol and explained different modes of Websocket communication, shown how to create a WebSocket connection, and invoke various JavaScript function to send/receive messages between client and server. This article also demonstrated the power of server-side callback functions within the CFCListener component, which you can use to help you to integrate with the core ColdFusion functionalities for WebSockets.
 
For further reading, I strongly recommend the following resources:
 
To learn more about the WebSocket functionality in ColdFusion visit the WebSocket Developer Guide.