DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Accelerating Connection Handshakes in Trusted Network Environments
  • Building REST API Backend Easily With Ballerina Language
  • Scalable Client-Server Communication With WebSockets and Spring Boot (Part II)
  • Rails 6: Multiple DB Support

Trending

  • Using Python Libraries in Java
  • Tired of Spring Overhead? Try Dropwizard for Your Next Java Microservice
  • The Smart Way to Talk to Your Database: Why Hybrid API + NL2SQL Wins
  • Enforcing Architecture With ArchUnit in Java
  1. DZone
  2. Data Engineering
  3. Data
  4. Real-Time Stock Data Updates with WebSockets using Ballerina

Real-Time Stock Data Updates with WebSockets using Ballerina

Simulation of real-time data updates with WebSockets. In this article, we'll implement a WebSocket-based service and clients using the Ballerina WebSocket module.

By 
Anupama Pathirage user avatar
Anupama Pathirage
DZone Core CORE ·
Updated Nov. 23, 21 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
24.9K Views

Join the DZone community and get the full member experience.

Join For Free

The internet is built on the HTTP standard for communicating data between clients and servers. Although HTTP is widely-used, when there is a requirement to support the continuous transmission of data streams or real-time updates between client and server, repeatedly making regular HTTP requests will slow things down.

Messaging on the Internet

Before discussing the real power and use of WebSocket let’s see what are the different ways of messaging on the internet. 

Request-Response - In traditional HTTP-based systems the communication can be initiated in one direction, that is from the client to the server. Webserver receives and responds to the requests from the clients via HTTP messages. 

  • HTTP is stateless, as it treats each new request as completely independent.  
  • HTTP request-response behavior is not sufficient when the client needs real-time updates.

Short polling - This is for clients to get regular updates from the server. The client sends a request to the server to get the updates, and the server responds with new data or no new data response. Then client repeats the same request at a configured interval to get new data. 

  • The protocol is simple and it uses widely supported HTTP. 
  • But the drawback is the request overhead on both sides as the client has to initiate lots of requests and the server has to handle a lot of such requests whether or not there is new information. 

Long polling - This is an improved version of short polling. The client sends an HTTP request for new information to the server. Then Server waits until there’s new information to respond (a “hanging” response). The client repeats the request as soon as it gets the previous response back.  

  • This is more efficient than short polling as it produces less traffic and it is simple as it uses HTTP.
  • But now the server has to hold unfulfilled requests and it can take more server resources. Also if there are multiple open requests from the same client, message ordering can’t be guaranteed, and messages can get lost. 

Server sent Events - This provides a one-way connection for a server to push new data to a client, without reestablishing a connection every time. 

  • This is good for apps where we don’t need to send the server any data—for example, a Twitter-style news feed or a real-time dashboard of stock quotes. 
  •  But this doesn’t support bi-directional data communication.

Websockets - WebSockets is a two-way message-passing protocol (full-duplex) based on TCP and faster for data transmission than HTTP because it has less protocol overhead and operates at a lower level in the network stack.  First, the client and server establish a connection over HTTP and then “upgraded” using the WebSockets handshake. Then WebSockets TCP messages are transmitted in both directions over port 443 (or 80 if it’s not TLS encrypted).

Websocket is defined in RFC 6455.

                                           Comparison of Different Messaging Mechanisms

How Websocket Works

Websocket protocol has two parts as the initial handshake and then the data transfer. For the initial communication, WebSocket uses HTTP. In this HTTP request client ask to open a WebSocket connection and it is an HTTP upgrade request which includes a few required headers as follows. 

 
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket


Then if the server is able to use WebSocket it will reply and the handshake is successful. The successful handshake demonstrates that the client and server are in agreement for using the existing TCP/IP connection established for the HTTP request as a WebSocket connection. Then it keeps the TCP connection alive after the HTTP response is received and that will be used for sending messages between client and server after that. 

WebSocket URIs use a new scheme ws: (or wss: for a secure WebSocket)

Simulating Real-Time Stock Updates Using WebSockets

Now, let’s explore what we can do with WebSockets in real life. Social feeds, multiplayer games, financial feeds, location-based updates, multimedia chat are a few common examples of WebSocket usage. Let’s implement a demo stock update service using the Ballerina programming language.  If Ballerina is not installed already, follow the instructions here and install Ballerina. Refer to the following video for more details:

Use Case 

The WebSocket-based stock management server is getting stock data feed via WebSocket-based connections from different exchanges. The client applications will subscribe to the preferred stock symbols by registering those symbols with the stock management server. 

When the stock management server receives updates to the subscribed symbols, it will broadcast the data to the subscribed clients using a WebSocket connection. 

                                                             Stock Update Use Case


Stock Management Server

Following is the stock management server implementation and save it in a file named ws_stock_mgt_server.bal

Java
 
import ballerina/websocket;
import ballerina/io;
import ballerina/regex;

isolated map<websocket:Caller[]> clientSymbolSubscriptionMap = {};

listener websocket:Listener stockMgtListner = new websocket:Listener(9090);

service /subscribe on stockMgtListner {
    //Accepts the websocket upgrade from clients by returining a websocket:service
    resource function get .() returns websocket:Service|websocket:UpgradeError {
        return new WsSubscribeService();
    }
}

service /feed on stockMgtListner {
    //Accepts the websocket upgrade from exchange feed by returining a websocket:service
    resource function get .() returns websocket:Service|websocket:UpgradeError {
        return new WsStockFeedService();
    }
}

//Websocket service to handle client subscriptions
service class WsSubscribeService {
    *websocket:Service;

    //Register the client
    remote function onOpen(websocket:Caller caller) returns websocket:Error? {
        string message = "Client with ID :" + caller.getConnectionId() + " registered successfully!";
        check caller->writeTextMessage(message);
        io:println(message);
    }

    //Register the symbol subscriptions of client.
    isolated remote function onTextMessage(websocket:Caller caller, string symbol) returns websocket:Error? {
        lock {
            websocket:Caller[]? clientList = clientSymbolSubscriptionMap[symbol];
            if clientList is websocket:Caller[] {
                clientList.push(caller);
            } else {
                clientSymbolSubscriptionMap[symbol] = [caller];
            }
        }
        io:println("Client " + caller.getConnectionId() + " subscribed for " + symbol);
    }
}

//Websocket service to handle incoming exchange data feed and broadcast to subscribed clients
service class WsStockFeedService {
    *websocket:Service;

    //Register the stock exchange feed
    remote function onOpen(websocket:Caller caller) returns websocket:Error? {
        string message = "Exchange with ID :" + caller.getConnectionId() + " registered successfully!";
        check caller->writeTextMessage(message);
        io:println(message);
    }

    //Receives exchange feed from the exchange and send the updates to registered clients
    isolated remote function onTextMessage(websocket:Caller caller, string text) returns error? {
        string[] result = regex:split(text, ":");
        string symbol = result[0];
        string price = result[1];

        lock {
            if (clientSymbolSubscriptionMap.hasKey(symbol)) {
                websocket:Caller[] clients = clientSymbolSubscriptionMap.get(symbol);
                foreach websocket:Caller c in clients {
                    check c->writeTextMessage(symbol + ":" + price);
                }
            }
        }
    }
}


Client

Following is the demo client implementation which sends subscriptions for a few stock symbols. Save the code in a file named client.bal.

Java
 

import ballerina/io;
import ballerina/lang.runtime;
import ballerina/websocket;

public function main() returns error? {
    websocket:Client wsClient = check new (string `ws://localhost:9090/subscribe/`);
    string message = check wsClient->readTextMessage();
    io:println(message);

    //Subscribe for `MSFT` symbol
    check wsClient->writeTextMessage("MSFT");

    //Subscribe for `GOOG` symbol later
    runtime:sleep(20);
    check wsClient->writeTextMessage("GOOG");

    //Read stock updates received from the server
    while true {
        string stockPrice = check wsClient->readTextMessage();
        io:println(stockPrice);
    }
}


Exchange

This is the exchange feed simulator that sends stock updates every 2 seconds. Save the code in a file named exchange.bal.

Java
 
import ballerina/io;
import ballerina/lang.runtime;
import ballerina/random;
import ballerina/websocket;

string[] symbolArr = ["MSFT", "AAPL", "GOOG", "NFLX", "CSCO"];

public function main() returns error? {
    websocket:Client wsClient = check new (string `ws://localhost:9090/feed/`);
    string message = check wsClient->readTextMessage();
    io:println(message);

    //Calculate dummy prices for each symbol randomly and send to server in every 2 seconds
    while true {
        int randomSymbolIndex = check random:createIntInRange(0, 5);
        float price = random:createDecimal() + 18.0;
        string stockData = symbolArr[randomSymbolIndex] + ":" + price.toString();
        io:println(stockData);
        check wsClient->writeTextMessage(stockData);
        runtime:sleep(2);
    }
}


Running the Applications

Let's run the three applications using the below commands in the following order.

bal run ws_stock_mgt_server.bal. 

bal run client.bal

bal run exchange.bal

You will see an output similar to below.

Stock Management Server

You can see both the client and exchange WebSocket clients have registered. And, the client has sent subscriptions for two stock symbols. 

Stock Management Server application

Client

After subscribing to the symbols, the client will wait for the symbol updates. You can see the client is receiving updates only for the supported symbols.

Client application

Exchange

The exchange is sending the stock updates for the supported symbols by the exchange.

Exchange application

Summary

Websocket is a good choice for the full-duplex data communication requirements. In this article, we implemented a WebSocket-based service and clients using the Ballerina WebSocket module. Refer to the following resources for more details.

  • Ballerina WebSocket Module
  • Ballerina Examples
WebSocket Data (computing) Ballerina (programming language) Requests Connection (dance)

Opinions expressed by DZone contributors are their own.

Related

  • Accelerating Connection Handshakes in Trusted Network Environments
  • Building REST API Backend Easily With Ballerina Language
  • Scalable Client-Server Communication With WebSockets and Spring Boot (Part II)
  • Rails 6: Multiple DB Support

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!