Table of Contents

WebSockets

Overview

WebSocket support in Sparkle enables real-time, bidirectional communication between clients and servers. WebSockets are essential for applications that require instant data updates, such as chat applications, live notifications, and real-time data feeds. This chapter covers how to enable and use WebSockets in your server applications, focusing on the key operations such as upgrading HTTP requests to WebSocket connections, sending and receiving data, and managing WebSocket states.

If you're unfamiliar with WebSockets, you can learn more about the protocol on the WebSocket Wikipedia page.

Note

WebSockets are only available for Delphi XE8 or newer.

Key Operations

Upgrading an HTTP Request to WebSocket

To handle WebSocket connections, you first need to upgrade the incoming HTTP request to a WebSocket connection. This is done using the Upgrade method from the IWebSocketUpgrader interface. The upgrader checks if the incoming request is a WebSocket request and, if so, upgrades it to a WebSocket connection.

Example:

var
  Upgrader: IWebSocketUpgrader;
  WebSocket: IWebSocket;
begin
  Upgrader := THttpServerContext.Current.Item<IWebSocketUpgrader>;
  if Upgrader <> nil then
    WebSocket := Upgrader.Upgrade;
end;
  • Upgrader: The IWebSocketUpgrader instance retrieved from the current HTTP context.
  • Upgrade: If the request is a WebSocket request, the Upgrade method upgrades the connection and returns an instance of IWebSocket for managing the connection.

Sending and Receiving Data

Once the connection is upgraded, you can start sending and receiving WebSocket messages using the Send, Receive, SendFrame, and ReceiveFrame methods from the IWebSocket interface. Sparkle provides two primary methods for handling WebSocket communication:

  1. Send / Receive: These methods handle full WebSocket messages, automatically managing fragmented messages.

Sending a Message:

WebSocket.Send('Hello, WebSocket!');

Receiving a Message:

var
  Msg: IWebSocketMessage;
begin
  Msg := WebSocket.Receive;
  if Msg.MessageType = TWebSocketMessageType.Text then
    Log('Received: ' + Msg.Text);
end;
  1. SendFrame / ReceiveFrame: These methods allow for lower-level control by sending and receiving individual WebSocket frames. This is useful when you need to manage fragmented messages manually.

Sending a Frame:

WebSocket.SendFrame(Buffer, Count, TWebSocketMessageType.Text, EndOfMessage);

Receiving a Frame:

var
  Result: TWebSocketReceiveResult;
begin
  Result := WebSocket.ReceiveFrame(Buffer, Count);
  if Result.EndOfMessage then
    Log('Message received.');
end;
Warning

If you use SendFrame / ReceiveFrame, you must ensure that a full message is sent or received before switching to Send / Receive methods. Mixing these methods improperly can cause errors, as Send / Receive expects a complete message.

Managing WebSocket State

The State property from the IWebSocket interface provides access to the current state of the WebSocket connection, represented by the TWebSocketState enumeration.

  • State: The State property returns the current state of the WebSocket connection.

      if WebSocket.State = TWebSocketState.Open then
        Log('Connection is open.');
    
  • Close / SendClose: To close the WebSocket connection, use the Close method to initiate the closing handshake, or SendClose to respond to a received close frame.

      WebSocket.Close(WebSocketStatusCodes.NormalClosure);
    

Example: Implementing a WebSocket Service

Here is an example of how to implement a WebSocket service that echoes messages back to the client:

[ServiceImplementation]
TWebSocketService = class(TInterfacedObject, IWebSocketService)
private
  procedure Echo;
end;

procedure TWebSocketService.Echo;
var
  Upgrader: IWebSocketUpgrader;
  WebSocket: IWebSocket;
  Msg: IWebSocketMessage;
begin
  // Check if the request is a WebSocket request and upgrade it
  Upgrader := THttpServerContext.Current.Item<IWebSocketUpgrader>;
  if Upgrader = nil then
  begin
    TXDataOperationContext.Current.Handler.SetStatusCode(400);
    Exit;
  end;

  // Upgrade the connection to WebSocket
  WebSocket := Upgrader.Upgrade;

  // Echo received messages back to the client
  while WebSocket.State = TWebSocketState.Open do
  begin
    Msg := WebSocket.Receive;
    case Msg.MessageType of
      TWebSocketMessageType.Text:
        WebSocket.Send('Echo: ' + Msg.Text);
      TWebSocketMessageType.Close:
        WebSocket.SendClose(WebSocketStatusCodes.NormalClosure);
    end;
  end;
end;

initialization
  RegisterServiceType(TWebSocketService);

Explanation:

  • Upgrade Request: The Echo method checks if the incoming request is a WebSocket request and upgrades it if necessary.
  • Send / Receive: Once the connection is upgraded, the server enters a loop, receiving messages and echoing them back to the client.
  • SendClose: When a close frame is received from the client, the server responds with SendClose to complete the handshake and close the connection gracefully.

For further reading, you can check out more details about WebSockets on Wikipedia.