WebSocket Client Guide

pubnub share

WebSocket clients are essential components in modern web applications, enabling real-time communication between the client and server. By understanding the WebSocket protocol, developers can create robust applications that make the most of this powerful technology.

This blog, aimed at beginners, features WebSocket client implementations for some of the most popular client-side languages as well as an explanation of the standard WebSocket API events that are applicable for all implementations.

What is a WebSocket client?

A WebSocket client establishes a connection with a WebSocket server; this connection is a bidirectional, full-duplex communication channel, allowing the client and server to exchange two-way data simultaneously. WebSocket clients can be implemented in all popular programming languages, such as JavaScript, Python, Swift, and more.

Websocket clients typically use the WebSocket protocol (WSS) to interact with WebSocket servers. This protocol is designed to work over the same ports as HTTP and HTTPS (ports 80 and 443, respectively) on top of TCP, and uses a WebSocket handshake to establish a connection. Once the connection is established, the WebSocket client can send and receive messages through the onmessage event handler/callback.

WebSocket refers to the technology itself, while the WebSocket client represents the implementation of this technology within an application. WebSocket clients are responsible for initializing the connection, handling incoming messages, and managing the connection's lifecycle (onopen, onmessage, onerror, and onclose events). WebSockets are different from HTTP, so rather than making an HTTP request to an HTTP server, you are connecting to a WebSocket server.

How to use WebSocket clients

Using a WebSocket client effectively requires understanding its lifecycle events and handling them.

Initializing a WebSocket client

To initialize a WebSocket client, you need to create a new WebSocket object with the desired endpoint (URI) as a parameter. The endpoint should be the address of the WebSocket server you want to connect to. For example, in JavaScript:

const websocket = new WebSocket("ws://my-socket-server:80");

Handling WebSocket events

There are four main events defined in the WebSocket specification associated with clients: onopen, onmessage, onerror, and onclose. You should define event handlers to manage these events in your web application. 

Other parameters are also available such as the subprotocol, authentication, and sending binary data but the above events are enough to get started. WebSockets do not allow you to specify any custom headers.

Closing a WebSocket connection

To close a WebSocket connection, simply call the close() method on the WebSocket object:

websocket.close();

This will trigger the onclose event, allowing you to perform any necessary cleanup tasks.

Types of WebSocket clients

All major languages have a WebSocket implementation, either as part of the language itself or provided by a standard or popular package. The code examples below give the typical implementation of a WebSocket client in different programming languages and, where appropriate, provide dependencies.

Python WebSocket client

To create a WebSocket client in Python, you can use the WebSocket library as follows:

import websocket

def on_message(ws, message):
    print("Received message:", message)

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

def on_close(ws):
    print("Connection closed")

def on_open(ws):
    ws.send("Hello, websocket server!")

if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://localhost:8080",
                                 on_message=on_message,
                                 on_error=on_error,
                                 on_close=on_close)
    ws.on_open = on_open
    ws.run_forever()

C# WebSocket client

C# provides a WebSocket client through its ClientWebSocket class, which is part of the System.NET.WebSockets namespace.

This code below will connect to a WebSocket server at wss://my-websocket-server.com. Once the connection is established, it listens for messages, displays them on the console, and sends a reply back to the server.

using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WebSocketClientExample
{
    class Program
    {
        private static async Task Main(string[] args)
        {
            Uri serverUri = new Uri("wss://my-websocket-server.com");
            await ConnectWebSocketAsync(serverUri);
            Console.ReadKey();
        }

        private static async Task ConnectWebSocketAsync(Uri serverUri)
        {
            using (ClientWebSocket webSocket = new ClientWebSocket())
            {
                await webSocket.ConnectAsync(serverUri, CancellationToken.None);
                Console.WriteLine("WebSocket connection opened");

                _ = Task.Run(async () =>
                {
                    while (webSocket.State == WebSocketState.Open)
                    {
                        WebSocketReceiveResult result;
                        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
                        do
                        {
                            result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
                            string message = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
                            Console.WriteLine("Received message: " + message);
                        }
                        while (!result.EndOfMessage);
                    }
                });

                // Send a message to the WebSocket server
                string sendMessage = "Hello, WebSocket Server!";
                ArraySegment<byte> sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(sendMessage));
                await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                Console.WriteLine("Sent message: " + sendMessage);
            }
        }
    }
}

JavaScript WebSocket client

JavaScript is a widely-adopted language for client-side web development. Creating a WebSocket client in JavaScript / HTML is straightforward, as the language natively supports the WebSocket API.

const websocket = new WebSocket("wss://my-websocket-server.com");

websocket.onopen = function(event) {
  console.log("Connected!");
  websocket.send("Hello, WebSocket server!");
};

websocket.onmessage = function(event) {
  console.log("Received message:", event.data);
};

websocket.onerror = function(event) {
  console.log("Error:", event);
};

websocket.onclose = function(event) {
  console.log("Connection closed");
};

Node.js WebSocket client

Node.js is a popular runtime environment for executing JavaScript on the server side. To create a WebSocket client in Node.js, you can use the 'ws' library.

const WebSocket = require('ws');
const websocket = new WebSocket('wss://my-websocket-server.com');

websocket.on('open', function open() {
  console.log('Connected!');
  websocket.send('Hello, WebSocket server!');
});

websocket.on('message', function incoming(message) {
  console.log('Received message:', message);
});

websocket.on('error', function error(err) {
  console.log('Error:', err);
});

websocket.on('close', function close() {
  console.log('Connection closed');
});

React WebSocket client

This example creates a simple WebSocket client component in React that connects to a WebSocket server when the component is mounted, listening for messages and updating its state accordingly. The sendMessage function sends a message to the WebSocket server.

import React, { useState, useEffect } from 'react';

const WebSocketClient = () => {
  const [messages, setMessages] = useState([]);
  const [ws, setWs] = useState(null);

  useEffect(() => {
    const websocket = new WebSocket('wss://my-websocket-server.com');
    
    websocket.onopen = () => {
      console.log('WebSocket connection opened');
    };

    websocket.onmessage = (event) => {
      const newMessage = event.data;
      setMessages((prevMessages) => [...prevMessages, newMessage]);
    };

    websocket.onclose = () => {
      console.log('WebSocket connection closed');
    };

    websocket.onerror = (error) => {
      console.error('WebSocket error:', error);
    };

    setWs(websocket);

    return () => {
      websocket.close();
    };
  }, []);

  const sendMessage = (message) => {
    if (ws) {
      ws.send(message);
    }
  };

  return (
    <div id='myDiv'>
      <h2>WebSocket Client</h2>
      <ul>
        {messages.map((message, index) => (
          <li key={index}>{message}</li>
        ))}
      </ul>
      <button onClick={() => sendMessage('Hello, WebSocket Server!')}>
        Send Message
      </button>
    </div>
  );
};

export default WebSocketClient;

Swift WebSocket client

The following code uses the URLSessionWebSocketTask API to establish a WebSocket connection, listen for messages, and print them to the console. The sendMessage function will send a message to the WebSocket server and the connection is disconnected after a 5-second delay.

import Foundation

class WebSocketClient {
    private let url: URL
    private var webSocketTask: URLSessionWebSocketTask?

    init(url: URL) {
        self.url = url
    }

    func connect() {
        let session = URLSession(configuration: .default)
        webSocketTask = session.webSocketTask(with: url)
        webSocketTask?.resume()
        receiveMessage()
    }

    func disconnect() {
        webSocketTask?.cancel(with: .goingAway, reason: nil)
    }

    private func receiveMessage() {
        webSocketTask?.receive { [weak self] result in
            switch result {
            case .success(let message):
                switch message {
                case .string(let text):
                    print("Received message: \(text)")
                case .data(let data):
                    print("Received data: \(data)")
                @unknown default:
                    print("Unknown message")
                }
                self?.receiveMessage()
            case .failure(let error):
                print("Error receiving message: \(error)")
            }
        }
    }

    func sendMessage(_ message: String) {
        webSocketTask?.send(.string(message)) { error in
            if let error = error {
                print("Error sending message: \(error)")
            } else {
                print("Sent message: \(message)")
            }
        }
    }
}

let serverUrl = URL(string: "wss://my-websocket-server.com")!
let webSocketClient = WebSocketClient(url: serverUrl)
webSocketClient.connect()

// Send a message to the WebSocket server
webSocketClient.sendMessage("Hello, WebSocket Server!")

// Disconnect after a delay
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    webSocketClient.disconnect()
}

Golang WebSocket client

This simple example of a WebSocket client written in Go uses the popular github.com/gorilla/websocket package. It establishes a WebSocket connection, listens for messages, and prints them to the console. The client sends a message to the WebSocket server every second and the connection is closed when an interrupt signal (e.g., Ctrl+C) is received.

package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/websocket"
)

var interrupt chan os.Signal

func main() {
	interrupt = make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	u := url.URL{Scheme: "ws", Host: "my-websocket-server.com", Path: "/"}
	fmt.Printf("Connecting to %s\n", u.String())

	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	done := make(chan struct{})

	go func() {
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("Error during reading message:", err)
				return
			}
			fmt.Printf("Received: %s\n", message)
		}
	}()

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-done:
			return
		case t := <-ticker.C:
			err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
			if err != nil {
				log.Println("Error during writing message:", err)
				return
			}
			fmt.Printf("Sent: %s\n", t.String())
		case <-interrupt:
			log.Println("Interrupt received, closing connection")
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("Error during closing connection:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			return
		}
	}
}

Building real-time apps using WebSocket clients

By leveraging WebSocket clients, developers can create powerful and responsive applications that cater to modern user demands. Real-time applications can range from chat applications and online gaming to live data streaming and collaborative platforms.

Here are some steps to follow when building real-time applications using WebSocket clients:

  1. Choose the right programming language: Depending on your application's requirements and your preference, select a programming language that supports WebSocket clients. As discussed earlier, popular choices include JavaScript, Python, and React.

  2. Implement a WebSocket server: Besides the WebSocket client, you'll need a WebSocket server to manage incoming connections and handle data exchange. This server can be implemented in the same language as your WebSocket client or a different one, depending on your needs.

  3. Design your application's architecture: Carefully plan your application's structure, including defining message formats (e.g., JSON), establishing connection management strategies (e.g., reconnecting after disconnections), and designing the user interface (UI) to handle real-time updates.

  4. Handle WebSocket events: As discussed earlier, handling WebSocket events such as onopen, onmessage, onerror, and onclose is crucial for managing the lifecycle of WebSocket connections. Implement the required event handlers in your application to exchange messages and handle errors.

PubNub and WebSocket clients

PubNub is a powerful platform that simplifies the process of building real-time applications. With its data streaming and messaging capabilities, PubNub enables seamless communication between client-side and server-side components without the developer having to worry about the underlying communication mechanism. By leveraging PubNub's features, developers can focus on building their applications without worrying about the complexities of implementing clients and servers from scratch.

Here are some benefits of using PubNub for building real-time applications:

To start using PubNub, visit our tutorials page for step-by-step guides and code examples. You can also explore the developer documentation and API reference for more in-depth information.

Further Reading

For more resources on WebSocket clients, check out these links: