Custom Protocol — Files — Technical Document
sgcWebSockets · Technical Document

Custom Protocol — Files

File-transfer custom subprotocol — chunked, resumable upload and download over WebSocket with progress notifications.

Overview

This protocol allows sending files using binary WebSocket transport. It can handle big files with a low memory usage.

At a glance

Component class
TsgcWSPClient_Files
Standards / spec
Transports
WebSocket, WebSocket Secure
Platforms
Windows, macOS, Linux, iOS, Android
Frameworks
VCL, FireMonkey, Lazarus / FPC, .NET
Edition
Professional / Enterprise

Features

Technical specification

Component classTsgcWSPClient_Files (unit sgcWebSocket_Protocols, ancestor TsgcWSProtocol_Files_Client in unit sgcWebSocket_Protocol_Files_Client)
FrameworksVCL, FireMonkey, Lazarus / FPC, .NET
PlatformsWindows, macOS, Linux, iOS, Android

Main properties

The principal published / public properties used to configure and drive the component. Consult the online help for the full list.

ClientWebSocket client component used as transport for the Files subprotocol.
BrokerOptional broker component that forwards file-protocol traffic through a shared client transport.
FilesFile-transfer settings collection covering buffer size, save directory and QoS.
GuidIdentifier used by the server to route file-protocol traffic to this client instance.
VersionRead-only sgcWebSockets library version string.

Main methods

The principal public methods exposed by the component.

Subscribe()Subscribes this client to a channel so it receives file-protocol notifications published on it.
UnSubscribe()Cancels a previous Subscribe so the client no longer receives messages from the channel.
SendFile()Uploads a file to the server in fragmented chunks with configurable QoS.
WriteData()Sends a plain text message to the server over the Files subprotocol.

Public events

The component exposes the following published events; consult the online help for full event-handler signatures.

OnBinaryFires when a raw binary frame arrives through the Files subprotocol transport.
OnConnectFires after the WebSocket handshake completes and the Files subprotocol is ready to transfer files.
OnDisconnectFires when the transport connection drops; the subprotocol stops its QoS timer and optionally clears the pending streams.
OnErrorFires for transport-level errors reported by the underlying sgcWebSocket client.
OnExceptionFires when an unhandled exception is raised inside the subprotocol worker or QoS timer thread.
OnFileBeforeSentFires just before the file header leaves the client, letting you inspect or tweak the outgoing TsgcWSMessageFile.
OnFileReceivedFires when an incoming file has been fully received and persisted to disk.
OnFileReceivedAuthorizationTsgcWSPClient_Files › Events › OnFileReceivedAuthorization
OnFileReceivedErrorproperty OnFileReceivedError: TsgcWSFileErrorEvent; // TsgcWSFileErrorEvent = procedure(Connection: TsgcWSConnection; const aMessage: TsgcWSMessageFile; const Error: String) of object __property TsgcW...
OnFileReceivedFragmentFires every time a new fragment of an incoming file has been written to disk; ideal for progress indicators.
OnFileSentFires when the server confirms that a file has been fully received.
OnFileSentAcknowledgmentFires when the server acknowledges processing of an outbound file fragment under qosLevel1 or qosLevel2.
OnFileSentErrorFires when the upload of a file fails either locally or after a rejection from the server.
OnFileSentFragmentRequestFires each time the client is about to send a new outbound file fragment; ideal for upload progress and cancellation.
OnFragmentedFires for every fragmented WebSocket frame passing through the Files subprotocol transport.
OnMessageFires when a plain text message arrives inside a Files subprotocol envelope.
OnRawMessageFires with the untouched incoming text before the subprotocol parses it; set Handled to stop default processing.
OnSubscriptionFires when the server confirms a channel subscription requested with Subscribe.
OnUnSubscriptionFires when the server confirms that a channel subscription has been cancelled.

Quick Start

Drop the component on a form, configure the properties below and activate it. The snippet that follows shows the typical Files subprotocol client and server pair configuration.

About this scenario. Pair a TsgcWSPServer_Files with a TsgcWebSocketServer and a TsgcWSPClient_Files with a TsgcWebSocketClient. The Files property carries the transfer settings, BufferSize is the size of each chunk, SaveDirectory is where incoming files are written, and QoS.Level selects the delivery guarantee. Subscribe to a channel first, then call SendFile.

Delphi (VCL / FireMonkey)

// --- server side
oServer := TsgcWebSocketServer.Create(nil);
oServer.Port := 80;
oServerFiles := TsgcWSPServer_Files.Create(nil);
oServerFiles.Server := oServer;
oServerFiles.Files.SaveDirectory := 'C:\server\inbox\';
oServer.Active := True;

// --- client side
oClient := TsgcWebSocketClient.Create(nil);
oClient.Host := '127.0.0.1';
oClient.Port := 80;
oClientFiles := TsgcWSPClient_Files.Create(nil);
oClientFiles.Client := oClient;
oClientFiles.Files.BufferSize := 8192;
oClientFiles.Files.SaveDirectory := 'C:\inbox\';
oClientFiles.Files.QoS.Level := qosLevel1;
oClientFiles.OnFileSent := OnFileSentEvent;
oClientFiles.OnFileReceived := OnFileReceivedEvent;
oClient.Active := True;

oClientFiles.Subscribe('files');
oClientFiles.SendFile('C:\data\report.pdf');

C++ Builder

// --- server side
oServer = new TsgcWebSocketServer(this);
oServer->Port = 80;
oServerFiles = new TsgcWSPServer_Files(this);
oServerFiles->Server = oServer;
oServerFiles->Files->SaveDirectory = "C:\\server\\inbox\\";
oServer->Active = true;

// --- client side
oClient = new TsgcWebSocketClient(this);
oClient->Host = "127.0.0.1";
oClient->Port = 80;
oClientFiles = new TsgcWSPClient_Files(this);
oClientFiles->Client = oClient;
oClientFiles->Files->BufferSize = 8192;
oClientFiles->Files->SaveDirectory = "C:\\inbox\\";
oClientFiles->Files->QoS->Level = qosLevel1;
oClientFiles->OnFileSent = OnFileSentEvent;
oClientFiles->OnFileReceived = OnFileReceivedEvent;
oClient->Active = true;

oClientFiles->Subscribe("files");
oClientFiles->SendFile("C:\\data\\report.pdf");

.NET (C#)

// --- server side
oServer = new TsgcWebSocketServer();
oServer.Port = 80;
oServerFiles = new TsgcWSPServer_Files();
oServerFiles.Server = oServer;
oServerFiles.Files.SaveDirectory = @"C:\server\inbox\";
oServer.Active = true;

// --- client side
oClient = new TsgcWebSocketClient();
oClient.Host = "127.0.0.1";
oClient.Port = 80;
oClientFiles = new TsgcWSPClient_Files();
oClientFiles.Client = oClient;
oClientFiles.Files.BufferSize = 8192;
oClientFiles.Files.SaveDirectory = @"C:\inbox\";
oClientFiles.Files.QoS.Level = TwsQoS.qosLevel1;
oClientFiles.OnFileSent += OnFileSentEvent;
oClientFiles.OnFileReceived += OnFileReceivedEvent;
oClient.Active = true;

oClientFiles.Subscribe("files");
oClientFiles.SendFile(@"C:\data\report.pdf");

Common scenarios

Each scenario shows the configuration and method calls needed to drive the component through a specific real-world flow. Every identifier below is taken from the component declaration shipped with the library.

1 · Receiving a file and authorising it first

Every incoming transfer raises OnFileReceivedAuthorization before a single byte is written. The handler receives the proposed file name in a var parameter, so you can rename the file, and an Accept flag you can clear to refuse the transfer. Progress arrives on OnFileReceivedFragment, completion on OnFileReceived, and failures on OnFileReceivedError.

Delphi (VCL / FireMonkey)
procedure TForm1.OnFileReceivedAuthorizationEvent(Connection: TsgcWSConnection;
  const aMessage: TsgcWSMessageFile; var aFileName: string;
  var Accept: Boolean);
begin
  Accept := ExtractFileExt(aMessage.FileName) <> '.exe';
  aFileName := 'received_' + aMessage.FileName;
end;

procedure TForm1.OnFileReceivedFragmentEvent(Connection: TsgcWSConnection;
  const aMessage: TsgcWSMessageFile; var Cancel: Boolean);
begin
  ProgressBar1.Position :=
    Round(aMessage.FilePosition / aMessage.FileSize * 100);
end;

procedure TForm1.OnFileReceivedEvent(Connection: TsgcWSConnection;
  const aMessage: TsgcWSMessageFile);
begin
  DoLog('received ' + aMessage.FileName);
end;
C++ Builder
void __fastcall TForm1::OnFileReceivedAuthorizationEvent(
  TsgcWSConnection *Connection, TsgcWSMessageFile *aMessage,
  String &aFileName, bool &Accept)
{
  Accept = ExtractFileExt(aMessage->FileName) != ".exe";
  aFileName = "received_" + aMessage->FileName;
}

void __fastcall TForm1::OnFileReceivedFragmentEvent(
  TsgcWSConnection *Connection, TsgcWSMessageFile *aMessage, bool &Cancel)
{
  ProgressBar1->Position =
    (int)(aMessage->FilePosition * 100 / aMessage->FileSize);
}

void __fastcall TForm1::OnFileReceivedEvent(TsgcWSConnection *Connection,
  TsgcWSMessageFile *aMessage)
{
  DoLog("received " + aMessage->FileName);
}
.NET (C#)
void OnFileReceivedAuthorizationEvent(TsgcWSConnection Connection,
  TsgcWSMessageFile MessageFile, ref string FileName, ref bool Accept)
{
  Accept = Path.GetExtension(MessageFile.FileName) != ".exe";
  FileName = "received_" + MessageFile.FileName;
}

void OnFileReceivedFragmentEvent(TsgcWSConnection Connection,
  TsgcWSMessageFile MessageFile, ref bool Cancel)
{
  progressBar1.Value =
    (int)(MessageFile.FilePosition * 100 / MessageFile.FileSize);
}

void OnFileReceivedEvent(TsgcWSConnection Connection,
  TsgcWSMessageFile MessageFile)
{
  DoLog("received " + MessageFile.FileName);
}

2 · Big files, chunk size and acknowledged delivery

Files.BufferSize sets the size of every fragment, so a large file is streamed in pieces rather than held in memory. Files.QoS.Level set to qosLevel1 or qosLevel2 makes the peer acknowledge each fragment, and Interval and Timeout control the retry cadence. The SendFile overload that takes an explicit size and QoS lets you override the component defaults for one transfer.

Delphi (VCL / FireMonkey)
oClientFiles.Files.BufferSize := 65536;
oClientFiles.Files.QoS.Level := qosLevel1;
oClientFiles.Files.QoS.Interval := 1000;
oClientFiles.Files.QoS.Timeout := 30000;
oClientFiles.Files.ClearSentStreamsOnDisconnect := False;

// per-transfer override: file name, chunk size, QoS, data, file id
oClientFiles.SendFile('C:\data\archive.zip', 65536, qosLevel1,
  '', 'archive-1');
C++ Builder
oClientFiles->Files->BufferSize = 65536;
oClientFiles->Files->QoS->Level = qosLevel1;
oClientFiles->Files->QoS->Interval = 1000;
oClientFiles->Files->QoS->Timeout = 30000;
oClientFiles->Files->ClearSentStreamsOnDisconnect = false;

oClientFiles->SendFile("C:\\data\\archive.zip", 65536, qosLevel1,
  "", "archive-1");
.NET (C#)
oClientFiles.Files.BufferSize = 65536;
oClientFiles.Files.QoS.Level = TwsQoS.qosLevel1;
oClientFiles.Files.QoS.Interval = 1000;
oClientFiles.Files.QoS.Timeout = 30000;
oClientFiles.Files.ClearSentStreamsOnDisconnect = false;

oClientFiles.SendFile(@"C:\data\archive.zip", 65536,
  TwsQoS.qosLevel1, "", "archive-1");

3 · Sending a file from the server

On the server side SendFile takes the target connection Guid as its first argument, so you can push a file to one client. BroadcastFile sends the same file to every connected client, optionally narrowed to a channel.

Delphi (VCL / FireMonkey)
// push to one client, identified by its connection Guid
oServerFiles.SendFile(Connection.Guid, 'C:\server\out\manual.pdf');

// push to everyone
oServerFiles.BroadcastFile('C:\server\out\manual.pdf');
C++ Builder
oServerFiles->SendFile(Connection->Guid, "C:\\server\\out\\manual.pdf");

oServerFiles->BroadcastFile("C:\\server\\out\\manual.pdf");
.NET (C#)
oServerFiles.SendFile(Connection.Guid, @"C:\server\out\manual.pdf");

oServerFiles.BroadcastFile(@"C:\server\out\manual.pdf");

Sources used to build this document

Every external claim links back to a primary source. The online-help references decode the canonical deep-link the company maintains for this component.

Document scope. This document covers the publicly-documented surface of the Custom Protocol — Files component shipped with sgcWebSockets. For full property, method and event reference consult the online help linked above.