WebSockets Introduction
WebSocket provides full-duplex and persistent client/server communication over TCP. It enables JavaScript clients to open bi-directional socket connections to a server. The WebSocket protocol is currently supported in all major browsers.
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:
ws(s)://host:port/path
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.
An introduction to using WebSockets from JavaScript can be found on the web site HTML5 Rocks. Please consult the HTML5 Rocks's WebSockets tutorial if you need more information on how the JavaScript code works in the following example.
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.
- JavaScript code now running in the browser connects to the same server side LSP page, but this time, the browser sends a WebSocket request.
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 23: A function that implements a basic console print function. The function uses the jQuery JavaScript library for appending text to the HTML element on line 52.
- 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 2: The HTTP header Sec-WebSocket-Key is automatically set by the browser when the browser sends a WebSocket upgrade request to the LSP page. We simply use this construction to detect a WebSocket request. If it's not a WebSocket request, then the HTML and JavaScript code starting on line 18 is sent to the browser.
- 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.
Download similar WebSocket examples from GitHub.
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.
Why you should consider using SMQ and not raw WebSockets is explain in the tutorial Modern Approach to Embedding a Web Server in a Device
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. You may also want to check out the SMQ introduction, which provided a gentle introduction to SMQ pub/sub messaging.
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:
The client acting server code starts on line 19. The function send5Messages
's inner function "timeout
" is similar to the
loop in example 8.1, but uses a coroutine since we cannot block when using SMQ. We will cover coroutines in detail later.
The function simply loops 5 times, publishes a message to the JavaScript client running in the browser on line 27, and sleeps until the next timer
event on line 28. The timer coroutine starts as soon as function send5Messages
is called (line 32).
To get the example started, the client side JavaScript code is designed such that it publishes a "hello" message as soon as it starts.
The server side subscribes to this topic on line 36. When the client publishes the hello message, function send5Messages
is called.
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.