Websocket Handshaking Explained: Understanding the Key to Real-Time Communication

Websocket Handshaking Explained: Understanding the Key to Real-Time Communication

Real-time communication has become a crucial component of contemporary online applications in the digital era. Situations requiring constant, bidirectional data flow do not lend themselves to using conventional HTTP connections. This is where Websocket handshaking comes in—a protocol that provides quick and reliable connections, enabling smooth real-time communication between clients and servers. We will examine the foundations of Websocket handshaking, its essential elements, and present real-world examples using C# code in this blog article.

What is Websocket Handshaking? Websocket handshaking is a process that occurs when a client and server establish a Websocket connection. Unlike traditional HTTP, which follows a request-response model, Websocket handshaking enables bidirectional communication, allowing both the client and server to send and receive messages asynchronously.

The Websocket Handshake Process: The Websocket handshake process involves several steps that enable the establishment of a persistent and efficient communication channel:

a. HTTP Upgrade Request: The client initiates the handshake by sending an HTTP upgrade request to the server, indicating its intention to switch to the Websocket protocol.

b. Server Response: Upon receiving the upgrade request, the server responds with an HTTP 101 status code, indicating a successful upgrade to the Websocket protocol.

c. Headers and Key Generation: During the handshake, both the client and server exchange headers containing information required for establishing the Websocket connection. The client generates a random key, which is combined with a predefined Websocket GUID and then base64-encoded.

d. Verification and Acceptance: The server verifies the received key, constructs a response key by concatenating the client key with the GUID, and then base64-encodes it. If the server accepts the client’s request, it includes the response key in the response headers.

e. Connection Establishment: Once the client receives the server’s response, it verifies the response key to ensure the connection is established with the correct server. If the verification is successful, the Websocket connection is considered open and ready for bidirectional communication.

Implementing Websocket Handshaking in C#:

Setting Up the Server-Side: To implement Websocket handshaking in C#, we need to set up a server capable of handling Websocket connections. Here’s a basic example using the HttpListener class:

using System;
using System.Net;
using System.Net.WebSockets;
using System.Threading.Tasks;
class WebsocketServer
{
    private static async Task HandleWebsocketRequest(HttpListenerContext context)
    {
        if (context.Request.IsWebSocketRequest)
        {
            HttpListenerWebSocketContext websocketContext = await context.AcceptWebSocketAsync(null);
            
            // Websocket connection established, handle incoming messages here
            
            await websocketContext.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed", CancellationToken.None);
        }
        else
        {
            context.Response.StatusCode = 400; // Bad Request
            context.Response.Close();
        }
    }
    static void Main(string[] args)
    {
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:8080/");
        listener.Start();
        Console.WriteLine("Websocket server running...");
        while (true)
        {
            HttpListenerContext context = listener.GetContext();
            Task.Run(() => HandleWebsocketRequest(context));
        }
    }
}

Establishing a Websocket Connection: Once the server is set up, the client can establish a Websocket connection using the ClientWebSocket class. Here’s an example:

using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
class WebsocketClient
{
    static async Task Main(string[] args)
    {
        ClientWebSocket client = new ClientWebSocket();
        Uri serverUri = new Uri("ws://localhost:8080/");
        
        await client.ConnectAsync(serverUri, CancellationToken.None);
        // Websocket connection established, handle incoming and outgoing messages here
        await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed", CancellationToken.None);
    }
}

Sending and Receiving Messages: Once the Websocket connection is established, both the client and server can send and receive messages. Here’s an example of sending a message from the client:

string message = "Hello, server!";
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
await client.SendAsync(new ArraySegment<byte>(messageBytes), WebSocketMessageType.Text, true, CancellationToken.None);

To receive messages on the server-side, you can use a loop and the ReceiveAsync method:

byte[] buffer = new byte[1024];
while (websocketContext.WebSocket.State == WebSocketState.Open)
{
    WebSocketReceiveResult result = await websocketContext.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
    Console.WriteLine("Received message: " + message);
}

Closing the Websocket Connection: To close the Websocket connection, both the client and server can use the CloseAsync method:

await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection closed", CancellationToken.None);

Advanced Websocket Handshaking Concepts: In addition to the basic implementation, there are several advanced concepts related to Websocket handshaking that are worth exploring, such as authentication and authorization, securing Websocket connections using encryption, and scaling and load balancing for high-traffic applications.

Authentication and Authorization: To restrict access to Websocket connections, you can implement authentication and authorization mechanisms. This could involve validating user credentials during the handshake process or verifying access rights for specific Websocket endpoints.

Securing Websocket Connections: To enhance security, you can enable encryption for Websocket connections using protocols like Transport Layer Security (TLS) or Secure Sockets Layer (SSL). This ensures that the data exchanged between the client and server remains confidential and secure.

Scaling and Load Balancing: For applications that require handling a large number of Websocket connections, scaling and load balancing techniques can be employed. This involves distributing the incoming Websocket connections across multiple servers or instances to handle the increased load efficiently.

Conclusion

In order to enable real-time communication between clients and servers, websocket handshaking is essential. In this blog article, we looked at the basics of Websocket handshaking and included useful C# examples. You may unleash the power of real-time bidirectional communication in your web applications by comprehending and effectively implementing the Websocket handshake procedure. Websocket handshaking brings up a world of possibilities for developing dynamic and interactive experiences, whether it is chat apps, collaboration tools, or live updates.

Keep in mind to consult the official materials and other sources for a thorough knowledge of Websocket handshaking and how it is implemented in C#. Coding is fun!

Share this post

Comment (1)

  • John Reply

    I wish someone would create a step by step example like this but with WSS

    May 11, 2024 at 7:57 AM

Leave a Reply

Your email address will not be published. Required fields are marked *