New Built-in Websocket Server

In an increasingly connected world, websites or IoT applications must be updated in real-time.

A way to deliver information instantly to your sites is to use the Websocket protocol that provides a full-duplex communication channel between a server and a client. From the v20, 4D provides commands to create a Websocket server.

Commands to Create a Websocket Server

To manage your websocket server, 4D provides 2 new classes:

  • The first manages the server itself, 4D.WebSocketServer
  • The second manages the websocket connections: 4D.WebSocketConnection

 

To demonstrate this feature, let’s create a simple chat server!

Before using the websocket server class, your 4D webserver must be started!

4D.WebSocketServer

This class allows you to manage different events that occur on your server. To do so, you need to create a class with the below functions:

  • onConnection(), called when a new connection is requested.
  • onOpen(), called when the server starts
  • onTerminate(), called when the server stops
  • onError(), called when an error occurred.

In our example, we need first to manage the connection request. With the onConnection() function, you can cancel a connection by returning Null or an object that will be used to manage the message sent or received. In the example below, we return the WSConnectionHandler class (described in the next section):

Function onConnection($wss : Object; $param : Object) : Object
        // call the VerifyAddress method to verify if the remote address is allow to connect
	If (VerifyAddress($param.request.remoteAddress))
		// The connection is allowed
		// The WSConnectionHandler object returned is used 
		// by 4D to instantiate the 4D.WebSocketConnection object
		// related to this connection
		return cs.WSConnectionHandler.new() 
	Else 
		// The connection is canceled		
		return Null 
	End if 

Now, we want to log the start, close, and errors, so we create a WSServerHandler class:

Class constructor

Function onOpen($wss : Object; $param : Object)
LogFile("*** Server started")

Function onTerminate($wss : Object; $param : Object)
LogFile("*** Server closed")

Function onError($wss : Object; $param : Object)
LogFile("!!! Server error: "+$param.statusText)

4D.WebSocketConnection

This class allows you to manage different events during a given connection. To do so, you need to create a class with the below functions:

  • onMessage(), called each time a message arrives through this connection.
  • onOpen(), called when the 4D.WebSocketConnection object is created
  • onTerminate(), called when the 4D.WebSocketConnection object is terminated
  • onError(), called when an error occurred

 

To do our chat, this class will be the WSConnectionHandler class. It:

  • warns other users that a new user is connected when the connection is opened
  • warns other users that a user is disconnected when the connection is terminated
  • broadcast the received messages to all the other chat clients connected when a message is received.

 

Function onMessage($ws : 4D.WebSocketConnection; $message : Object)
	// resend the message to all the chat clients	
	This.broadcast($ws;$message.data)

Function onOpen($ws : 4D.WebSocketConnection; $message : Object)
	// Send a message to the new connected user 
	$ws.send("Welcome on the chat!")	
	// Send message "New client connected" to all the other chat clients
	This.broadcast($ws;"New client connected")

Function onTerminate($ws : 4D.WebSocketConnection; $message : Object)
	// Send message "Client disconnected" to all the other chat clients
	This.broadcast($ws;"Client disconnected")

Function broadcast($ws : 4D.WebSocketConnection; $message : Text)
	var $client:4D.WebSocketConnection
	// resend the message to all the chat clients
	For each ($client; $ws.wss.connections)
		// Verify that the id is not the current connection
		If ($client.id#$ws.id)
			$client.send($message)
		End if 
	End for each 

All left is to start the websocket server using the classes created above. You must create a new process with the CALL WORKER command and instantiate the 4D.WebSocketServer in it:

var $handler:cs.WSSHandler
$handler:=cs.WSServerHandler.new()

CALL WORKER("WebSocketServer"; Formula(WSS:=4D.WebSocketServer.new($handler)))

As you can see above, we use a GLOBAL variable (WSS) to store the instance of our created handler. This global variable will exists forever (because a worker will not stop to exits as a process would do) and as long the variable exists, our Web Socket Server will exists. If a local variable would be used or a normal process would be used, the server would be killed as soon the variable is not existing anymore.

Client-side

You can find below an example of code in HTML and Javascript to create a chat interface:

This code is designed to work with a local webserver at HTTP port 80 (line 18: const urlwss=”ws://127.0.0.1:80/”;).

Check out this feature with the HDI above and the documentation for more details!

Fabrice Mainguené
• Product Owner •Fabrice Mainguené joined 4D Program team in November, 2016. As a Product Owner, he is in charge of writing the user stories then translating it to functional specifications. His role is also to make sure that the feature implementation delivered is meeting the customer need.After obtaining a Bachelor degree in Computer Science at CNAM, Fabrice joined a small software publishing company as a Windev developer. Then he worked for different companies in industry and trade areas as a Windev and web developer as well as technical advisor on new features.