Taxonomy Icon

Analytics

Websocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. It is very flexible and can be used for transferring data to and from servers using a browser, Peer-to-Peer (P2P), or direct communication between browsers. WebSockets are used whenever you need a truly low latency, near realtime connection between the client and the server. Unlike HTTP, the socket that is connected to the server stays &open& for communication. That means data can be &pushed& to the browser in realtime on demand.

There are a number of WebSocket frameworks available per language like Socket.IO, Phpws, Ws4py, Nodejs-websocket etc. When usingB any of these, one has to write code to setup the websocket server as per the api format. This article will explain how to setup websockets with minimal programming using Node-RED. Node-RED is an open-source tool created by the IBM Emerging Technology team. Node-RED provides a browser-based editor that makes it easy to wire nodes together and that can be deployed to its runtime in a single-click.

Learning objectives

This tutorial will demonstrate:

  • The websockets communication between web interface and Jupyter notebook on IBM Watson Studio(Watson Studio).

  • How to setup a websocket server using Node-RED.

  • How to setup websocket clients.

Prerequisites

Before beginning this tutorial, you need the following:

Estimated Time

This tutorial will take approximately 30 minutes to complete. Setup of the websocket server on Node-RED and websocket clients will take 15 minutes and understanding how to use Node-RED for socket communication will be approximately 15 minutes.

Steps

Client-Server Communication between a Jupyter Notebook on IBM Watson Studio and a Web Interface

The below architecture diagram shows the client-server communication.

The following sections will explain each part of communication in detail.

Setup the Websocket Server on Node-RED

The websocket node in Node-RED comes in two flavors, input and output, allowing you to listen for incoming data (input) or to send (output) on a websocket. Both the input and output websocket nodes can be configured as either server or client – in server mode they blisten on’ a URL, and in client mode they connect to a specified IP address.

The node-red flow to create a server will be:

Here are three standard nodes – a websocket input node, a function node and a websocket output node.

Select a websocket input node and configure its type to be Listen on. Under Path add a new websocket-listener with the path /ws/receiveMessage. This flow will open a websocket service in the path. A websocket client can begin sending data to this service.

Select a websocket output node. Configure the type to be Listen on and add a new websocket-listener with the path /ws/publishMessage. This service is required to notify the client whenever the server wants to send a message.

Now, edit the function node in between the websocket nodes to transfer the message. This node will parse the message received by the /ws/receiveMessage websocket service and add it as payload to be sent to the /ws/publishMessage service. Add the following code in the function node:

return {payload: msg.payload};

When we have two clients (i.e. two browsers) sending and receiving data on the same Node-RED websocket, the message will be sent back to the client that triggered the flow. Otherwise, the message will be broadcast to all connected clients. In this scenario, we have two clients – a Jupyter notebook and a web browser, hence we need to broadcast the message.

To broadcast a message that started at a websocket input node, you should delete the msg._session property within the flow. To achieve this, edit the function node in between and add the following code:

msg._session = "";
return msg;

Then deploy the flow by clicking on the red Deploy button on the top of the page.

Setup the Websocket Client on a Web Interface

To setup the websocket client on a web interface, we will use a simple test web page with a field and a submit button that would send information to the websocket without refreshing the page and which would return the information to the same page.

It is convenient to have everything in Node-Red to serve up the web page as well as handling web sockets. Node-RED flow for this will be:

It has an HTTP in node, a Template to render an HTML page, and an HTTP out node for the response. The HTTP in node ([get] /access-url) creates an endpoint to receive GET requests and forwards those requests to the Template. The HTTP out node creates the proper response to be sent back to the user after the template has been rendered. Here, the middle node contains a standard webpage of your design and within that is the websocket connection.

Message handling is done using JavaScript. First, we open a connection to the websockets endpoint, created using Node-RED.

var socket1 = new  WebSocket("ws://<Node-RED Base URL>/ws/receiveMessage");
var socket2 = new  WebSocket("ws://<Node-RED Base URL>/ws/publishMessage");

This will create two new websocket objects pointing to two endpoints (receive and publish).

Notice how these URLs are prefixed with ws instead of http, and the proper way to use it is: ws://url.

Register event handlers for the websocket object to handle events like onOpen, onClose, onError etc. When the user sends a message the handler creates an object with the message and then sends it to the server using the send method on the service /ws/receiveMessage. When the server publishes a message on the service /ws/publishMessage, the onMessage() function is called.

socket2.onopen = function() {
  var message = {
    'cmd': 'Client connected'
  };
  socket1.send(JSON.stringify(message));
};

socket2.onclose = function(){
  console.log('Connection closed');
};

socket2.onerror = function(error) {
  console.log('Error detected: ' + error);
};

socket2.onmessage = function(e) {
  var server_message = e.data;
  responseObject = JSON.parse(server_message);

  alert(JSON.stringify(responseObject));
  //Do the required stuff
}

Here you can use the same websocket-listener name for the websocket input and output node, and the same websocket object will be used to handle all the events.

Setup Websocket Client on Jupyter Notebook

As explained in the previous section, to setup a websocket client we need to open a websocket connection and register event handlers for the websocket object to handle events. To setup websocket client in Jupyter notebook we need to do the same thing in python code.

def start_websocket_listener():
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://<Node-RED Base URL>/ws/<socket listener name>",
                              on_message = on_message,
                              on_error = on_error,
                              on_close = on_close)
    ws.on_open = on_open
    ws.run_forever()

def on_error(ws, error):
    print(error)

def on_close(ws):
    ws.send("Watson Studio Listen End")

def on_message(ws, message):
    print(message)
    # do the required stuff

To start the communication we need to start the websocket client as shown:

# To start socket client @notebook
start_websocket_listener()

Test the setup

Once you complete the setup for the clients and server, the flow is ready to test.

  • Deploy Node-RED flow for the server and web interface.

  • Start a websocket listener in Jupyter notebook.

  • Access the URL.

On loading of the webpage, Node-RED will show the websockets node as connected.

Now either client can send message to the server. The server will broadcast the message and it will be received by both clients. Messages should be handled properly and programmatically at both clients for appropriate action.

Summary

You have setup a websocket server on Node-RED and websocket clients on a web interface and on a Jupyter notebook on IBM Watson Studio. Deploy your flow and use it for your application.