sgcWebSockets 五分钟上手

您已经安装了库,组件面板也已显示。本页将带您从这里出发,搭建一个接受连接的服务器,以及一个发送消息并读取回复的客户端。下面的所有内容都来自下载包中自带的演示项目,因此您可以直接打开项目,而不必手动输入。

Delphi 7 到 RAD Studio 13
Windows、Linux、macOS、iOS、Android
客户端从 Standard 版起,服务器从 Professional 版起

第一个示例所需的内容

两个非可视组件,uses 子句中的一个单元,以及事件处理程序参数类型所需的另一个单元。

客户端组件

TsgcWebSocketClient,声明在 sgcWebSocket.pas 中,注册在 SGC WebSockets 组件面板页上。先设置 Host 和 Port,再设置 Active。

服务器组件

TsgcWebSocketServer,位于同一个单元和同一个组件面板页。先设置 Port,再设置 Active。它负责监听、升级握手并触发 OnConnect。

第二个单元

每个事件都会传给您一个 TsgcWSConnection,它位于 sgcWebSocket_Classes.pas 中。演示项目中写的是 uses sgcWebSocket, sgcWebSocket_Classes;,您也应该这样写。

平台

这两个单元都没有平台保护,两个组件也都使用 ComponentPlatforms(0) 注册,因此 VCL、FMX、控制台和服务目标都可以编译。安装包中还附带一个 FireMonkey 客户端演示。

要求与版本

版本列给出的是实际控制代码的定义,以及它在 Source/sgcVer.inc 中所在的行号。

项目 值
IDE Delphi 7 到 RAD Studio 13,以及 C++Builder 2007 到 13。每个 IDE 版本在 Packages\ 下都有一个包组。
uses 子句 组件使用 sgcWebSocket,TsgcWSConnection 使用 sgcWebSocket_Classes。
客户端版本 TsgcWebSocketClient 被包裹在 {$IFDEF SGC_WS_CLIENT} 中。SGC_WS_CLIENT 定义在第 697 行,位于从第 675 行延伸到第 724 行的 {$IFDEF SGC_EDT_STD} 块内。因此是 Standard 及以上版本。
服务器版本 TsgcWebSocketServer 直接包裹在 {$IFDEF SGC_EDT_PRO} 中,它在 sgcWebSocket_Reg.pas 中的组件面板注册也在同一个保护块内。Professional 功能块从第 727 行延伸到第 758 行。因此是 Professional 及以上版本。Standard 许可证提供客户端,不提供服务器。
组件面板页 在 {$IFDEF SGC_PACK_WEBSOCKETS} 下注册,该符号定义在第 852 行。
平台 sgcWebSocket.pas、sgcWebSocket_Client.pas 和 sgcWebSocket_Server.pas 中没有单元级平台保护。Windows 只是有条件地引入 Windows 单元,别无其他。

不确定您使用的是哪个版本?打开 Source/sgcVer.inc,查看前五行。其中的 SGC_EDT_* 定义是累加的,因此 All-Access 会定义全部,而 Standard 只定义前两个。

安装并确认组件面板

从压缩包到可放置的组件共五步。请先编译运行时包,再安装设计时包,因为后者引用前者。

1. 解压

将下载文件解压到您选择的文件夹。本页其余部分称该文件夹为 {$DIR}。Source\、Packages\、Demos\ 和 lib*\ 文件夹都在其下。

2. 库路径

依次选择 Tools、Options、Library。添加 {$DIR}\source 以及与您的 IDE 对应的文件夹,例如 RAD Studio 13 使用 {$DIR}\libD13\$(Platform),12 使用 {$DIR}\libD12\$(Platform)。

3. 构建包

针对您的 IDE 版本,打开 {$DIR}\Packages\sgcWebSocketsD13.groupproj。先编译 sgcWebSocketsD13.dpk,再安装 dclsgcWebSocketsD13.dpk。C++Builder 使用同一文件夹中的 .cbproj 文件。

4. 检查组件面板

会出现一个名为 SGC WebSockets 的新页面。在 Standard 构建中,它包含 TsgcWebSocketClient。在 Professional 及以上版本中,还包含 TsgcWebSocketServer、TsgcWebSocketHTTPServer、TsgcWebSocketProxyServer 和 TsgcWebSocketLoadBalancerServer。

5. 打开演示项目

在编写任何代码之前,先打开 {$DIR}\Demos\01.WebSocket_Quick_Start\01.Server_and_Client_Chat。它是库中最小的可运行配对,下面的代码就来自它。

一个服务器和一个客户端,大约二十行代码

启动服务器,启动客户端,发送一个字符串。服务器选项卡在一个端口上监听;客户端选项卡连接到该端口并写入一条消息。

uServerChat.pas
uses
  Classes, SysUtils,
  // sgc
  sgcWebSocket, sgcWebSocket_Classes;

procedure TfrmServerChat.btnStartClick(Sender: TObject);
begin
  WSServer.Port := 5418;
  WSServer.Active := True;
  memoLog.Lines.Add('#started');
end;

procedure TfrmServerChat.WSServerConnect(Connection: TsgcWSConnection);
begin
  memoLog.Lines.Add('Connected: ' + Connection.IP);
end;

procedure TfrmServerChat.WSServerDisconnect(Connection: TsgcWSConnection;
  Code: Integer);
begin
  memoLog.Lines.Add('Disconnected (' + IntToStr(Code) + '): ' + Connection.IP);
end;

procedure TfrmServerChat.WSServerMessage(Connection: TsgcWSConnection;
  const Text: string);
begin
  memoLog.Lines.Add(Text);
  // send it straight back, so the client has something to read
  Connection.WriteData('echo: ' + Text);
end;

将 TsgcWebSocketServer 放到窗体上,命名为 WSServer,然后让 IDE 通过对象检查器生成这四个处理程序。Connection.IP 和 Connection.WriteData 都来自 TsgcWSConnection,这就是 sgcWebSocket_Classes 要出现在 uses 子句中的原因。

uClientChat.pas
uses
  Classes, SysUtils,
  // sgc
  sgcWebSocket, sgcWebSocket_Classes;

procedure TfrmClientChat.btnStartClick(Sender: TObject);
begin
  WSClient.Host := 'localhost';
  WSClient.Port := 5418;
  WSClient.TLS := False;
  WSClient.Active := True;
end;

procedure TfrmClientChat.btnSendClick(Sender: TObject);
begin
  if WSClient.Active then
    WSClient.WriteData('Hello from Delphi')
  else
    raise Exception.Create('Not connected');
end;

procedure TfrmClientChat.WSClientConnect(Connection: TsgcWSConnection);
begin
  memoLog.Lines.Add('#connected');
end;

procedure TfrmClientChat.WSClientMessage(Connection: TsgcWSConnection;
  const Text: string);
begin
  memoLog.Lines.Add(Text);
end;

先运行服务器项目,再运行这个项目。客户端日志中会出现 #connected,并且 echo: Hello from Delphi 会通过 OnMessage 返回。这个往返过程就是整个快速入门。

uConsole.pas
program WSConsoleClient;

{$APPTYPE CONSOLE}

uses
  Classes, SysUtils,
  // sgc
  sgcWebSocket, sgcWebSocket_Classes;

type
  TChatHandler = class
    procedure DoConnect(Connection: TsgcWSConnection);
    procedure DoMessage(Connection: TsgcWSConnection; const Text: string);
  end;

procedure TChatHandler.DoConnect(Connection: TsgcWSConnection);
begin
  Writeln('#connected');
end;

procedure TChatHandler.DoMessage(Connection: TsgcWSConnection;
  const Text: string);
begin
  Writeln('Server says: ', Text);
end;

var
  oClient: TsgcWebSocketClient;
  oHandler: TChatHandler;
begin
  oHandler := TChatHandler.Create;
  oClient := TsgcWebSocketClient.Create(nil);
  try
    oClient.Host := 'localhost';
    oClient.Port := 5418;
    oClient.WatchDog.Enabled := True;   // reconnect on its own

    // assign the handlers BEFORE Active, or the first
    // OnConnect can fire with nothing attached
    oClient.OnConnect := oHandler.DoConnect;
    oClient.OnMessage := oHandler.DoMessage;

    oClient.Active := True;
    oClient.WriteData('Hello from Delphi');
    Readln;
  finally
    oClient.Free;
    oHandler.Free;
  end;
end.

客户端运行在自己的线程中,因此控制台程序必须保持主线程存活。这正是 Readln 的作用。

服务器和客户端选项卡取自随包附带的演示 Demos\01.WebSocket_Quick_Start\01.Server_and_Client_Chat,并去掉了演示中复选框和编辑框相关的代码。第三个选项卡使用相同的调用,但针对的是在运行时创建的组件,而不是放在窗体上的组件。

验证往返流程

四个事件能说明首次运行的全部情况,在继续之前,您需要把这四个事件都连接好。

Active

在服务器上,Active := True 要么成功,要么抛出异常。如果端口已被占用,您会在这里发现,而不是三步之后。

OnConnect

procedure(Connection: TsgcWSConnection)。两端都会触发。在服务器上,Connection.IP 会告诉您是谁连接了进来;在客户端上,它证明握手已经升级。

OnMessage

procedure(Connection: TsgcWSConnection; const Text: string)。客户端收到返回的回显,就证明了端到端的往返流程。

OnError 和 OnException

procedure(Connection: TsgcWSConnection; const Error: string) 和 procedure(Connection: TsgcWSConnection; E: Exception)。两者都要连接。没有它们,故障会悄无声息,看起来就像什么都没发生。

第一次通常会出什么问题

几乎所有首次运行的问题都是下面这六种之一。

组件面板上没有 TsgcWebSocketServer

服务器类只有在定义了 SGC_EDT_PRO 时才会编译(位于 sgcWebSocket.pas 第 130 行),并且只在同一个保护块内注册。在 Standard 构建中,有客户端而没有服务器。这是许可证的限制,而不是安装损坏。

未声明的标识符 TsgcWSConnection

组件位于 sgcWebSocket,连接对象位于 sgcWebSocket_Classes。请把第二个单元添加到 uses 子句中。所有随包附带的演示都同时包含这两个单元。

客户端连接后又断开

设置 WatchDog.Enabled := True,让断开的连接自动重连,并处理 OnError 和 OnException。没有处理程序的静默断开看起来就像什么都没发生。

服务器收不到任何数据

写入之前,先确认客户端确实已经连通。在未激活的客户端上调用 WriteData 没有任何作用,这就是演示在发送之前先检查 if WSClient.Active then 的原因。

端口已被占用

服务器的另一个实例或其他程序仍然占用着该端口。请停止它,或者将服务器改到空闲端口。演示的默认端口是 5416 和 5418。

在 Linux 或移动平台上 TLS 失败

wss:// 连接需要可用的 TLS 后端。通过 TLSOptions.IOHandler 选择一个:OpenSSL 适用于所有平台,SChannel 适用于 Windows 且无需部署 DLL,或者使用 Enterprise 版中的 Apple 和 Android 原生处理程序。

发出第一条消息之后,大家通常会去哪里

聊天配对只是起点。下面是工作通常会延伸的四个方向,而且这四个方向都在同一个库中。

使用真正的协议

同一个客户端可以承载 MQTT、AMQP、STOMP、Kafka 和 WAMP 子协议组件。放置其中一个,将它的 Client 属性指向您的 TsgcWebSocketClient,就可以连接到代理了。

sgcMQ 快速入门和协议概览

同时提供 HTTP 和 WebSocket 服务

TsgcWebSocketHTTPServer 在同一个端口上响应普通 HTTP 请求和 WebSocket 升级,当浏览器需要先获取页面再打开套接字时,这正是您想要的。

HTTP 组件

扩展到多个进程

Enterprise 版增加了集群、负载均衡器服务器和代理服务器,因此单个逻辑端点可以位于多个服务器进程之前。

集群参考和负载均衡器参考

发布前加固

速率限制、断路器、API 密钥管理器和防火墙组件都可以附加到您现有的服务器上。

速率限制器、断路器和防火墙

参考、演示和文档

参考页面记录了每个属性和事件。演示项目就在您的下载包内,位于 Demos\01.WebSocket_Quick_Start 下。

参考:WebSocket 客户端 TsgcWebSocketClient 上的每个属性、方法和事件。
参考:WebSocket 服务器 TsgcWebSocketServer 上的绑定、身份验证、广播和连接管理。
在线帮助:TsgcWebSocketClient 自动生成的组件参考,始终与当前版本保持同步。
我需要哪个版本 逐项说明 Standard、Professional、Enterprise 和 All-Access 各自启用的功能。
下载试用版 与正式版相同的安装程序,有时间限制,每个 IDE 版本一个。
用户手册(PDF) 涵盖库中每个组件的完整手册。

相关阅读:WebSocket 到底是什么、客户端连接和 WatchDog 事件,以及保护 WebSocket 服务器。每个产品都有自己的快速入门,列在入门页面上。

sgcWebSockets 快速入门常见问题

sgcWebSocket 提供 TsgcWebSocketClient 和 TsgcWebSocketServer。还要添加 sgcWebSocket_Classes,因为每个事件都会传给您一个 TsgcWSConnection,而该类型就声明在那里。随包附带的演示写的是 uses sgcWebSocket, sgcWebSocket_Classes;,服务器演示还额外添加了 sgcWebSocket_Server。
服务器类在 {$IFDEF SGC_EDT_PRO} 内编译,它在 sgcWebSocket_Reg.pas 中的组件面板注册也位于同一个保护块内。SGC_EDT_PRO 会开启 Professional 功能块,即 sgcVer.inc 的第 727 行到第 758 行。Standard 构建只编译客户端。客户端定义 SGC_WS_CLIENT 位于第 697 行,在 Standard 块(第 675 行到第 724 行)之内。
它们来自 sgcWebSocket_Classes.pas。OnConnect 是 procedure(Connection: TsgcWSConnection)。OnDisconnect 是 procedure(Connection: TsgcWSConnection; Code: Integer)。OnMessage 是 procedure(Connection: TsgcWSConnection; const Text: string)。OnError 是 procedure(Connection: TsgcWSConnection; const Error: string)。OnException 是 procedure(Connection: TsgcWSConnection; E: Exception)。请让 IDE 生成它们,而不要手动输入,因为多一个或少一个参数是第一个项目中最常见的编译错误。
可以。sgcWebSocket.pas、sgcWebSocket_Client.pas 和 sgcWebSocket_Server.pas 没有单元级平台保护,两个组件也都使用 ComponentPlatforms(0) 注册,因此 IDE 不会把它们限制在某个目标平台上。FireMonkey 客户端和服务器演示位于 Demos\01.WebSocket_Quick_Start\07.Firemonkey_Server_and_Client。库中唯一有平台限制的 WebSocket 组件是 TsgcWebSocketClient_WinHTTP,仅支持 Win32 和 Win64。
在客户端上设置 TLS := True,并将 Port 指向 TLS 端口。然后通过 TLSOptions.IOHandler 选择 TLS 后端。OpenSSL 适用于所有平台,在 Windows 上需要把 libcrypto-3.dll 和 libssl-3.dll 放在可执行文件旁边。SChannel 仅适用于 Windows,无需额外文件。Apple 和 Android 原生处理程序是 Enterprise 功能。
可以,上面的第三个选项卡就是这样做的。请在设置 Active := True 之前分配事件处理程序,否则第一个 OnConnect 可能在处理程序附加之前就已触发。在控制台应用程序中,请记住客户端运行在自己的线程中,因此主线程必须保持存活,这就是示例以 Readln 结尾的原因。
它会按您选择的时间间隔重新连接已断开的客户端。对于任何长时间运行的程序都应启用它,否则一次导致套接字关闭的网络波动会让您的应用程序悄无声息地处于断开状态。设置 WatchDog.Enabled := True,如果默认值过于频繁,可再调整 WatchDog.Interval 和 WatchDog.Attempts。
在您的下载包内,位于 Demos\ 下。本页使用的配对是 01.WebSocket_Quick_Start\01.Server_and_Client_Chat。同样值得尽早打开的有:06.Authentication(检查凭据的服务器)、07.Firemonkey_Server_and_Client(跨平台客户端)和 12.Groups(向一部分连接广播)。
超值之选:All-AccesseSeGeCe 全部产品,含高级支持,每年 €1,059 起。
查看 All-Access 价格

准备好开始构建了吗?

下载试用版,在编写自己的第一行代码之前先运行聊天演示。