The main characteristic of WebSockets is the ability to perform bi-directional communication without breaking the connection. WebSocket connections are basically TCP socket connections that following the WebSocket rules to communicate. The WebSocket Protocol initially starts as an HTTP(S) connection and is morphed into an independent TCP-based protocol when the server and client have completed the initial Websocket handshake. Morphing the HTTP(s) connection into a persistent (secure) TCP connection is in WebSocket terminology called a "WebSocket Upgrade".
A WebSocket URL looks like this:
The connection is made to the host on the given port number. You do not need to specify the port number if the server is using the default port numbers 80 and 443. The protocol starts with ws for non secure communication and wss for secure (SSL) communication. A WebSocket URL must always be an absolute URL, even when connecting back to the origin server.
Note that the server side LSP page in the following example is accessed twice by the browser when you click the run button:
- The web application starting on line 18 is loaded into the browser.
Clicking the above Run button should start the WebSocket connection if your browser supports WebSockets. You should see printouts in the server's console window and in the example's iframe above.
Example 8.1 Client Code:
- Line 26: We construct an absolute WebSocket URL by using server side code. Method request:url returns the URL of the LSP page. We apply a Lua regular expression and replaces http(s) with ws(s) on the returned string.
- Line 27: A URL modification required by the LSP example engine. This code is specific for the embedded tutorial engine, and you would not use this construction in a standard LSP page. The URL encoded parameters make it possible for the server side LSP example engine to route the WebSocket request to the LSP code for example 8.1.
- Line 30: We wrap the creation of the client side WebSocket object into a try/catch. The code fails if the browser does not support WebSockets and "s" will be undefined on line 31 if we get an exception.
- Lines 35 - 36: We construct the WebSocket object's callback functions.
Example 8.1 Server Code:
- Line 4: Function ba.socket.req2sock morphs the HTTP request into a WebSocket connection -- in other words, it performs the WebSocket upgrade management. The function returns a socket object if the upgrade is successful. Note that calling function ba.socket.req2sock invalidates the request/response object and you can no longer use these two objects after calling this function.
- Line 6 - 11: We loop 5 times and for each iteration we do: send a message to the client and make the current thread sleep one second. At this point, we are still running in the context of one of the server's HTTP threads. The server keeps a pool of threads and we are using one thread for sending WebSocket data to the client. Please note that in a real case scenario, you would normally set the WebSocket in non blocking mode and immediately release the HTTP thread. In our basic example, we simply keep the HTTP thread working for 5 seconds before releasing the thread.
- Line 13-14: when we are done looping, the socket is closed and we return out of the LSP page, thus releasing the HTTP thread.
See Designing Socket Protocols in Lua in the Barracuda App Server documentation if you want to get a deeper understanding of how to use WebSockets.
Using SMQ for WebSocket Communication
Simple Message Queues is a pub-sub protocol that uses WebSockets for the communication between browsers and the server. In fact, the SMQ broker, is built by using cosockets provided by the server. The protocol's documentation focuses on IoT communication for devices, but the SMQ protocol can also be used for browser to server communication and vice versa. The broker provides an API that enables Lua code running on the server side to act as an SMQ client; thus you can easily design communication channels between browsers and the server.
The following example requires some understanding of the Lua scope and using coroutines so you may want to take a look at these two tutorials (Scope and Coroutine) prior to running the two following examples.
The SMQ example is split up into two parts: the server side in example 8.2 and the client side in example 8.3. The two examples are designed to provide the same features as example 8.1. Only the server sends data and the server keeps sending 5 messages before stopping. Notice that we cannot disconnect the connection from the server as we did in example 8.1 so the server side simply goes quiet after sending 5 messages.
The SMQ URL:
The SMQ connection sequence initially starts as HTTP(S), and it's common to use an LSP page as the URL destination. Due to how the example engine works, we have in the following example used a server directory function and a directory instance instead of an LSP page. We create an SMQ broker instance on line 1 below. The directory function on line 3 simply redirects the incoming request to the broker. We create a directory on line 8-10 and insert the directory into the virtual file system.
Server side code acting as client:
Click the run button above to install the server side code. The client side code in the next example will not run unless the server side is installed.
The client side code, which runs in the browser, is shown in example 8.3.
The connection to the broker on the server is established on line 10. The helper function SMQ.wsURL translates a relative URL to an absolute URL required by WebSockets. Notice that the relative URL corresponds to the location in the server's virtual file system where we install the broker in example 8.2.
We subscribe to "self" on line 4. Self means subscribing to the client's ephemeral ID and makes it possible for the server to send a message directly to the client. This message is sent on line 27 in example 8.2.
We publish to the topic "hello" on line 15 to start the send5Messages function on the server side.
Clicking the above run method should show a hello message being printed 5 times, with a one second pause between each printed line.
See the Internet of Things demos/tutorials for more information on how to use SMQ.