【问题标题】:How to continuously send messages with TIdTCPServer?如何使用 TIdTCPServer 连续发送消息?
【发布时间】:2015-02-18 19:41:19
【问题描述】:

我需要创建一个 delphi 应用程序,当它启动时服务器也会启动并立即开始发送消息,但我还没有找到示例或教程,而且近 5000 页的 Indy 手册并没有明确说明我该怎么做...

【问题讨论】:

  • 服务器如何知道何时启动?或者它会通过手动过程启动,换句话说,你?或者服务器是否已经在等待接受消息?
  • 您有已经尝试过的代码吗?或者您是从没有尝试的空白页面开始?
  • @BlurrySterk 创建表单后,它将启动服务器。我还没有这方面的代码,因为我找不到任何可以使用的示例。

标签: delphi indy


【解决方案1】:

这个例子使用一个 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/

【讨论】:

    【解决方案2】:

    Indy 的工作方式是让客户端 (TidTCPClient) 连接到服务器 (TidTCPServer),然后在它们之间来回交换数据,直到连接被故意或提前断开连接终止。

    我在这里仅指实际的 Indy TCP 组件,而不是您查看应用程序的方式。

    在应用程序级别,您可能会认为一个应用程序是服务器应用程序,而另一个应用程序是客户端应用程序,但两者都可以/可能包含它们与其他应用程序通信的 TidTCPClient 和 TidTCPServer 组件。这意味着服务器应用程序可以通过服务器应用程序的 TidTCPClient 组件发起与客户端应用程序的连接,并且客户端应用程序将通过其 TidTCPServer 组件接收连接。这将是一个可能的解决方案,但请记住,通常客户端是动态的并且不断变化,而服务器通常是静态的,因此跟踪客户端的位置将是一项任务。太多的头疼和太多的工作。

    所以我认为最好让客户端跟踪他们很少更改的服务器,因此最好为服务器应用程序提供一个 TidTCPServer 组件并让它在开始发送消息之前等待客户端连接。

    所以要实施;您的客户端必须不断尝试定期连接到服务器,直到找到服务器。然后,服务器可以发送任意数量的消息,直到被要求停止或直到过早断开连接,在这种情况下,循环将重新启动。 Indy 有一些方法可以跟踪客户端连接,您可以通过这些方法保留客户端的内部列表。这更有意义。这是大多数客户端-服务器应用程序的工作方式。想想 Skype 和任何 Web 服务器。客户端联系服务器并在需要时接收数据。

    在服务器端:

    • 创建 TidTCPServer 对象。
    • 设置 TidTCPServer 监听一个或多个本地 IP 地址并为其选择 IP 端口。
    • 将代码分配给 TidTCPServer,它将在客户端运行时立即运行 通过 TidTCPServer 的 OnExecute 连接到它。在此代码中,您将向连接的客户端发送消息。
    • 激活 TidTCPServer 使其处于侦听模式。

    在客户端:

    • 创建一个 TidTCPClient 对象。
    • 设置 TidTCPClient 以使用特定的主机和端口(IP 服务器的地址/主机名和您选择的端口)
    • 在有间隔的重复循环中尝试连接到服务器。
    • 一旦建立连接,客户端就可以发送 服务器某些东西或立即尝试从连接中读取 如果服务器发送一些东西,它将收到什么

    这种类型的操作有很多例子。您必须先尝试,如果您遇到困难,您可以随时针对您遇到的问题提出问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      相关资源
      最近更新 更多