WebSockets is a relatively new technology which enables full-duplex communication in web sites or web applications. A standard web application uses HTTP protocol which is a half-duplex communication protocol. Server always is in listen mode and serves incoming requests from the clients. In the conventional HTTP protocol there is no way for the server to directly send data to the clients. In order to update the client view in the browser, client should continuously ask the server and get the new updates if there are any. This method is called polling the server. Polling is normally done using a JavaScript timer which regularly sends Ajax requests to the server. If there are any new updates the data is sent back to the client.
There are some disadvantages to use polling method:
•Clients should continuously send Ajax requests to server which means server needs to handle a huge number of Ajax requests if there are too many clients.
•Updates can only occur when there is an Ajax request. There is no way to update the client asynchronously. For example, if timer is set to fire each 30 seconds, client updates can only occur at 30 second intervals.
In order to overcome this limitation WebSocket technology was introduced about 10 years ago. Actually, WebSocket is not a new technology. Basically, it is just another TCP channel opened between client and the server. Unlike HTTP protocol where TCP connections can be temporary, a WebSocket connection is always open and ready to send & receive data. Client browser is able to receive messages from server through a WebSocket connection. It will enable server to send instant messages to the clients so polling mechanisms no longer will be needed.
uniGUI integrates WebSockets technology to enable developers send messages directly to web clients from the server. uniGUI implementation of WebSockets technology is very straightforward. Sending messages from server to clients can be done by using a method named BroadcastMessage(). When this method is called a message and related parameters will be broadcast through uniGUI network using WebSocket channels. This broadcast will include all Nodes and slave servers in a server farm cluster. uniGUI automatically relays the messages to all server instances which are active in a server farm cluster. Each server sends the messages to its own web clients. So no matter how complicated is your server farm cluster, uniGUI will ensure that all sessions will receive the messages.
For example using below syntax a message named 'update' will be sent to all existing clients.
BroadcastMessage('update');
When this message is received by a web client, that client fires an Ajax request to the server. Consequently on server side an event handler named OnBroadcastMessage will be called:
procedure TMainForm.UniFormBroadcastMessage(const Sender: TComponent; const Msg: string;
const Params: TUniStrings);
begin
if Msg = 'update' then
begin
UniLabel1.Caption := Query1.RecordCount.ToString;
end;
end;
In above example a UniLabel is updated each time a message is received. It is updated to show current record count of a database query.
The message is sent from server side and immediately reaches all the active sessions. Source of the message can be almost anywhere. It can be a user event or any other thread in the system. Evidently, messages can be sent asynchronously from any thread in the application. It is possible to use a thread timer to broadcast messages in regular time intervals. In a HyperServer cluster a message which is initiated from a Node will be propagated through all the servers in the cluster. It will be done automatically by the HyperServer no matter how big or complicated your cluster structure is.
Live Examples!
Below are few live examples running inside frames. Each frame contains a uniGUI web application session.
Chat Demo
On top two frames we have a simple chat application using WebSockets to instantly transferring chat messages to all existing sessions. You can simply test it by typing something in the related field and pressing the Send button. You will notice that the message is immediately transferred to the other frame running the chat application. You can also open new instances of this web page in new browser tabs and observe that chat messages are delivered to all chat session in open browser tabs.
Chat demo application
Chat demo application
If we examine chat application we can see that how simple is the underlying code. In below code chat message is sent to rest of the clients using the BroadcastMessage method.
procedure TMainForm.UniButton1Click(Sender: TObject);
var
Msg, Nick : string;
begin
Msg := Trim(UniEdit1.Text);
if Msg <> '' then
begin
Nick := Trim(UniComboBox1.Text);
// update my memo
AddLine(Msg, Nick);
// update other sessions' memos
BroadcastMessage('chat',
[
'msg', Msg,
'nick', Nick
],
[boIgnoreCurrentSession]); // Send the message to other sessions only
end;
ActiveControl := UniEdit1;
end;
The chat message is broadcasted by server to all existing web sessions using WebSocket connections. When a web clients receives a WebSocket message it casts an Ajax event to the server which will be handled in a Delphi event handler as below:
procedure TMainForm.UniFormBroadcastMessage(const Sender: TComponent;
const Msg: string;
const Params: TUniStrings);
begin
if Msg = 'chat' then
AddLine(Params['msg'].AsString, Params['nick'].AsString);
end;
Client Update Demos
In uniGUI implementation of WebSockets there is a possibility to update web clients directly without a need to send Ajax requests to the server. In this scenario server sends data to all sessions (or selected sessions) using a WebSocket connections. When clients receive this data a client side JavaScript handler is called to notify the client. An event handler can be used to update client side UI elements directly.
In one of the frames there is a uniGUI application showing a Label continuously refreshed with current time and date. Looking at the underlying code reveals that there is a thread timer on server side which broadcasts current date and time to all sessions.
procedure TUniServerModule.UniThreadTimer1Timer(Sender: TObject);
begin
BroadcastMessage('update',
[
'value', FormatDateTime('dd/mm/yyyy hh:nn:ss', Now)
],
[boClientOnly]);
end;
On the client side there is a JavaScript event handler which is responsible to get server side data and update the screen label. This method eliminates the need to send an Ajax request to the server to update the label. Label is directly updated in the client side JavaScript code. If you notice there is an option in above code named boClientOnly. This means that WinSocket message should be processed on the client side and it won't fire an Ajax request.
function form.socketmessage(sender, msg, params, eOpts)
{
if (msg == 'update') {
MainForm.UniLabel1.setText(params.value);
}
}
Grid updated directly from the server
Time updated directly from the server
In the other frames there is another uniGUI application showing a grid continuously refreshed with random data from the server. It uses same principle as the previous example. There is a thread timer on server side which broadcasts an array with randomly generated data:
procedure TUniServerModule.UniThreadTimer1Timer(Sender: TObject);
var
ParamArr : TConstArray;
I, J : Integer;
begin
InitConstArray(ParamArr);
try
for I := 1 to GRD_ROW do
for J := 1 to GRD_COL do
AddToConstArray(ParamArr, [Format('%d_%d', [I, J]), Random(1000)] );
BroadcastMessage('update_grid', ParamArr, [boClientOnly]); // Message will be processed on client side event handler
finally
FreeConstArray(ParamArr); // This must be called to free array elements otherwise memory leak will occur
end;
end;
As expected on the client side there's a JavaScript method which updates grid cells with received data:
function form.socketmessage(sender, msg, params, eOpts)
{
if (msg == 'update_grid') {
var grd = MainForm.UniStringGrid1;
for (prop in params) {
arr = prop.split('_');
var row = grd.store.getAt(arr[0]); // row number
if (row) {
row.set(arr[1], params[prop]);
}
}
}
}
Please note that directly updating the client UI is an optional feature. It is not needed to use WebSockets functionality. Most applications just do fine by updating UI in a server side Ajax request as demonstrated in the chat demo application above. Directly updating the UI is needed when you want make fast and continuous updates to the UI and don't want to create additional Ajax traffic. It helps updating UI directly from the server with little overhead and avoids creating unnecessary Ajax traffic where applicable.