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:
- 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;
- 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.