如何使用 TIdTCPServer 持续发送消息?
How to continuously send messages with TIdTCPServer?
我需要创建一个 delphi 应用程序,当它启动时,服务器也会启动并立即开始发送消息,但我没有找到示例或教程,近 5000 页的 Indy 手册也没有请告诉我如何才能做到这一点...
这个例子使用了一个 Delphi 2009 VCL 应用程序,它有一个主窗体,它只包含一个可视化组件,一个名为“MemoLog”的 TMemo。
客户端和服务器都在 FormCreate 事件中启动。请注意,客户端代码不处理连接丢失,但这可以通过线程内单独的重新连接循环来实现。
procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
ExampleServer := TMyPushServer.Create;
ExampleServer.DefaultPort := 8088;
ExampleServer.Active := True;
ExampleClient := TMyPushClientThread.Create('localhost', 8088,
MemoLog.Lines);
end;
服务器
服务器代码使用了一个 TIdTCPCustomServer 子类,它等待一个随机时间,然后向客户端发送一个字符串。
function TMyPushServer.DoExecute(AContext: TIdContext): Boolean;
begin
Result := inherited;
// simulate hard work
Sleep(Random(3000));
AContext.Connection.IOHandler.WriteLn(
'Completed at ' + TimeToStr(Now), IndyTextEncoding_UTF8);
end;
客户
客户端代码使用 TThread 子类来异步 运行 而不会阻塞主 VCL 线程。它包含一个私有的 TIdTCPClient 实例,并定期尝试从连接中接收一个字符串。
...
S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
...
完整 Delphi 表单代码
下面是示例主窗体的完整代码。
unit Unit1;
interface
uses
IdCustomTCPServer, IdTCPClient, IdContext,
SysUtils, Classes, Forms, StdCtrls, Controls;
type
TMyPushClientThread = class(TThread)
private
TCPClient: TIdTCPClient;
FLog: TStrings;
public
constructor Create(AHost: string; APort: Word; ALog: TStrings);
destructor Destroy; override;
procedure Execute; override;
end;
TMyPushServer = class (TIdCustomTCPServer)
protected
function DoExecute(AContext: TIdContext): Boolean; override;
end;
TServerPushExampleForm = class(TForm)
MemoLog: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
ExampleClient: TMyPushClientThread;
ExampleServer: TMyPushServer;
end;
var
ServerPushExampleForm: TServerPushExampleForm;
implementation
uses
IdGlobal;
{$R *.dfm}
procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
ExampleServer := TMyPushServer.Create;
ExampleServer.DefaultPort := 8088;
ExampleServer.Active := True;
ExampleClient := TMyPushClientThread.Create('localhost', 8088, MemoLog.Lines);
end;
procedure TServerPushExampleForm.FormDestroy(Sender: TObject);
begin
ExampleServer.Free;
ExampleClient.Terminate;
ExampleClient.WaitFor;
ExampleClient.Free;
end;
{ TMyPushServer }
function TMyPushServer.DoExecute(AContext: TIdContext): Boolean;
begin
Result := inherited;
// simulate hard work
Sleep(Random(3000));
AContext.Connection.IOHandler.WriteLn(
'Completed at ' + TimeToStr(Now), IndyTextEncoding_UTF8);
end;
{ TMyPushClientThread }
constructor TMyPushClientThread.Create(AHost: string; APort: Word; ALog: TStrings);
begin
inherited Create(False);
FLog := ALog;
TCPClient := TIdTCPClient.Create;
TCPClient.Host := AHost;
TCPClient.Port := APort;
TCPClient.ReadTimeout := 500;
end;
destructor TMyPushClientThread.Destroy;
begin
TCPClient.Free;
inherited;
end;
procedure TMyPushClientThread.Execute;
var
S: string;
begin
TCPClient.Connect;
while not Terminated do
begin
S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
if not TCPClient.IOHandler.ReadLnTimedout then
begin
TThread.Queue(nil,
procedure
begin
FLog.Append(S);
end);
end;
end;
TCPClient.Disconnect;
end;
end.
(来自 https://mikejustin.wordpress.com/2014/04/19/indy-10-tidtcpserver-server-side-message-push-example/)
Indy 的工作方式是让客户端 (TidTCPClient) 连接到服务器 (TidTCPServer),然后在它们之间来回交换数据,直到连接被故意或过早断开连接终止。
我在这里仅指实际的 Indy TCP 组件,而不是指您查看应用程序的方式。
在应用程序级别,您可能会认为一个应用程序是服务器应用程序,另一个应用程序是客户端应用程序,但两者 can/may 都包含它们与其他应用程序通信的 TidTCPClient 和 TidTCPServer 组件。这意味着服务器应用程序可以通过服务器应用程序的 TidTCPClient 组件启动与客户端应用程序的连接,客户端应用程序将通过其 TidTCPServer 组件接收连接。这将是一个可能的解决方案,但请记住,通常客户端是动态的并且不断变化,而服务器通常是静态的,因此跟踪客户端的位置将是一项任务。太多的头痛和太多的工作。
所以我认为最好让客户端跟踪他们很少更改的服务器,因此最好为服务器应用程序提供一个 TidTCPServer 组件,并让它在开始发送消息之前等待客户端连接。
所以要实施;您的客户端将不得不不断尝试定期连接到服务器,直到找到服务器。然后服务器可以发送任意数量的消息,直到被要求停止或直到过早断开连接,在这种情况下,循环将重新开始。 Indy 中有一些方法可以跟踪客户端连接,您可以通过这些方法保留一个内部客户端列表。这更有意义。这是大多数客户端-服务器应用程序的工作方式。想想 Skype 和任何 Web 服务器。客户端联系服务器并在需要时接收数据。
在服务器端:
- 创建 TidTCPServer 对象。
- 设置 TidTCPServer 以侦听其一个或多个本地 IP
地址并为它们选择一个 IP 端口。
- 将代码分配给 TidTCPServer,它会 运行 一旦客户端
通过 TidTCPServer 的 OnExecute 连接到它。在此代码中,您将向连接的客户端发送消息。
- 激活 TidTCPServer 使其处于侦听模式。
客户端:
- 创建一个 TidTCPClient 对象。
- 设置 TidTCPClient 以使用特定的主机和端口(IP
Address/Host 服务器名称和您选择的端口)
- 在有间隔的重复循环中尝试连接到服务器。
- 一旦建立连接,客户端就可以发送
服务器或立即尝试从连接中读取
如果服务器发送某些东西,它会收到什么
这种操作有很多例子。您必须先尝试,如果遇到困难,您可以随时提出针对您遇到的问题的具体问题。
我需要创建一个 delphi 应用程序,当它启动时,服务器也会启动并立即开始发送消息,但我没有找到示例或教程,近 5000 页的 Indy 手册也没有请告诉我如何才能做到这一点...
这个例子使用了一个 Delphi 2009 VCL 应用程序,它有一个主窗体,它只包含一个可视化组件,一个名为“MemoLog”的 TMemo。
客户端和服务器都在 FormCreate 事件中启动。请注意,客户端代码不处理连接丢失,但这可以通过线程内单独的重新连接循环来实现。
procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
ExampleServer := TMyPushServer.Create;
ExampleServer.DefaultPort := 8088;
ExampleServer.Active := True;
ExampleClient := TMyPushClientThread.Create('localhost', 8088,
MemoLog.Lines);
end;
服务器
服务器代码使用了一个 TIdTCPCustomServer 子类,它等待一个随机时间,然后向客户端发送一个字符串。
function TMyPushServer.DoExecute(AContext: TIdContext): Boolean;
begin
Result := inherited;
// simulate hard work
Sleep(Random(3000));
AContext.Connection.IOHandler.WriteLn(
'Completed at ' + TimeToStr(Now), IndyTextEncoding_UTF8);
end;
客户
客户端代码使用 TThread 子类来异步 运行 而不会阻塞主 VCL 线程。它包含一个私有的 TIdTCPClient 实例,并定期尝试从连接中接收一个字符串。
...
S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
...
完整 Delphi 表单代码
下面是示例主窗体的完整代码。
unit Unit1;
interface
uses
IdCustomTCPServer, IdTCPClient, IdContext,
SysUtils, Classes, Forms, StdCtrls, Controls;
type
TMyPushClientThread = class(TThread)
private
TCPClient: TIdTCPClient;
FLog: TStrings;
public
constructor Create(AHost: string; APort: Word; ALog: TStrings);
destructor Destroy; override;
procedure Execute; override;
end;
TMyPushServer = class (TIdCustomTCPServer)
protected
function DoExecute(AContext: TIdContext): Boolean; override;
end;
TServerPushExampleForm = class(TForm)
MemoLog: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
ExampleClient: TMyPushClientThread;
ExampleServer: TMyPushServer;
end;
var
ServerPushExampleForm: TServerPushExampleForm;
implementation
uses
IdGlobal;
{$R *.dfm}
procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
ExampleServer := TMyPushServer.Create;
ExampleServer.DefaultPort := 8088;
ExampleServer.Active := True;
ExampleClient := TMyPushClientThread.Create('localhost', 8088, MemoLog.Lines);
end;
procedure TServerPushExampleForm.FormDestroy(Sender: TObject);
begin
ExampleServer.Free;
ExampleClient.Terminate;
ExampleClient.WaitFor;
ExampleClient.Free;
end;
{ TMyPushServer }
function TMyPushServer.DoExecute(AContext: TIdContext): Boolean;
begin
Result := inherited;
// simulate hard work
Sleep(Random(3000));
AContext.Connection.IOHandler.WriteLn(
'Completed at ' + TimeToStr(Now), IndyTextEncoding_UTF8);
end;
{ TMyPushClientThread }
constructor TMyPushClientThread.Create(AHost: string; APort: Word; ALog: TStrings);
begin
inherited Create(False);
FLog := ALog;
TCPClient := TIdTCPClient.Create;
TCPClient.Host := AHost;
TCPClient.Port := APort;
TCPClient.ReadTimeout := 500;
end;
destructor TMyPushClientThread.Destroy;
begin
TCPClient.Free;
inherited;
end;
procedure TMyPushClientThread.Execute;
var
S: string;
begin
TCPClient.Connect;
while not Terminated do
begin
S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
if not TCPClient.IOHandler.ReadLnTimedout then
begin
TThread.Queue(nil,
procedure
begin
FLog.Append(S);
end);
end;
end;
TCPClient.Disconnect;
end;
end.
(来自 https://mikejustin.wordpress.com/2014/04/19/indy-10-tidtcpserver-server-side-message-push-example/)
Indy 的工作方式是让客户端 (TidTCPClient) 连接到服务器 (TidTCPServer),然后在它们之间来回交换数据,直到连接被故意或过早断开连接终止。
我在这里仅指实际的 Indy TCP 组件,而不是指您查看应用程序的方式。
在应用程序级别,您可能会认为一个应用程序是服务器应用程序,另一个应用程序是客户端应用程序,但两者 can/may 都包含它们与其他应用程序通信的 TidTCPClient 和 TidTCPServer 组件。这意味着服务器应用程序可以通过服务器应用程序的 TidTCPClient 组件启动与客户端应用程序的连接,客户端应用程序将通过其 TidTCPServer 组件接收连接。这将是一个可能的解决方案,但请记住,通常客户端是动态的并且不断变化,而服务器通常是静态的,因此跟踪客户端的位置将是一项任务。太多的头痛和太多的工作。
所以我认为最好让客户端跟踪他们很少更改的服务器,因此最好为服务器应用程序提供一个 TidTCPServer 组件,并让它在开始发送消息之前等待客户端连接。
所以要实施;您的客户端将不得不不断尝试定期连接到服务器,直到找到服务器。然后服务器可以发送任意数量的消息,直到被要求停止或直到过早断开连接,在这种情况下,循环将重新开始。 Indy 中有一些方法可以跟踪客户端连接,您可以通过这些方法保留一个内部客户端列表。这更有意义。这是大多数客户端-服务器应用程序的工作方式。想想 Skype 和任何 Web 服务器。客户端联系服务器并在需要时接收数据。
在服务器端:
- 创建 TidTCPServer 对象。
- 设置 TidTCPServer 以侦听其一个或多个本地 IP 地址并为它们选择一个 IP 端口。
- 将代码分配给 TidTCPServer,它会 运行 一旦客户端 通过 TidTCPServer 的 OnExecute 连接到它。在此代码中,您将向连接的客户端发送消息。
- 激活 TidTCPServer 使其处于侦听模式。
客户端:
- 创建一个 TidTCPClient 对象。
- 设置 TidTCPClient 以使用特定的主机和端口(IP Address/Host 服务器名称和您选择的端口)
- 在有间隔的重复循环中尝试连接到服务器。
- 一旦建立连接,客户端就可以发送 服务器或立即尝试从连接中读取 如果服务器发送某些东西,它会收到什么
这种操作有很多例子。您必须先尝试,如果遇到困难,您可以随时提出针对您遇到的问题的具体问题。