简体   繁体   English

如何使用TIdTCPServer连续发送消息?

[英]How to continuously send messages with TIdTCPServer?

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

服务器推送示例申请表

This example uses a Delphi 2009 VCL application with a main form, which contains only one visual component, a TMemo named “MemoLog”. 此示例使用带有主窗体的Delphi 2009 VCL应用程序,该窗体仅包含一个可视组件,名为“MemoLog”的TMemo。

Client and server are both started in the FormCreate event. 客户端和服务器都在FormCreate事件中启动。 Note that the client code does not handle connection loss, but this can be implemented with a separate re-connect loop within the thread. 请注意,客户端代码不处理连接丢失,但这可以通过线程内的单独重新连接循环来实现。

procedure TServerPushExampleForm.FormCreate(Sender: TObject);
begin
  ExampleServer := TMyPushServer.Create;
  ExampleServer.DefaultPort := 8088;
  ExampleServer.Active := True;

  ExampleClient := TMyPushClientThread.Create('localhost', 8088,
    MemoLog.Lines);
end;

Server 服务器

The server code uses a TIdTCPCustomServer subclass which waits for a random time and then sends a string to the client. 服务器代码使用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;

Client 客户

The client code uses a TThread subclass to run asynchronously without blocking the main VCL thread. 客户端代码使用TThread子类异步运行,而不会阻塞主VCL线程。 It contains a private TIdTCPClient instance, and periodically tries to receive a string from the connection. 它包含一个私有TIdTCPClient实例,并定期尝试从连接接收字符串。

...
  S := TCPClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
...

Full Delphi Form Code 完整的德尔福表格代码

Below is the full code for the example main form. 下面是示例主窗体的完整代码。

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.

(From https://mikejustin.wordpress.com/2014/04/19/indy-10-tidtcpserver-server-side-message-push-example/ ) (来自https://mikejustin.wordpress.com/2014/04/19/indy-10-tidtcpserver-server-side-message-push-example/

The way that Indy works is to have the client (TidTCPClient) connect to the server (TidTCPServer) and then exchange data between them, back-and-forth until the connection is terminated either willfully or by premature disconnect. Indy工作的方式是让客户端(TidTCPClient)连接到服务器(TidTCPServer),然后在它们之间来回交换数据,直到连接被故意或过早断开连接。

I am only referring to the actual Indy TCP components here and not to the way you see your applications. 我这里仅指的是实际的Indy TCP组件,而不是您看到应用程序的方式。

At the application level you might consider an application the server app and another the client app but both can/may contain both TidTCPClient and TidTCPServer components with which they communicate with other apps. 在应用程序级别,您可以将应用程序视为服务器应用程序,将另一个应用程序视为客户端应用程序,但两者都可以/可能包含与其他应用程序通信的TidTCPClient和TidTCPServer组件。 This means that the server app can initiate a connection to a client app via the server app's TidTCPClient component and the client app will receive the connection via its TidTCPServer component. 这意味着服务器应用程序可以通过服务器应用程序的TidTCPClient组件启动与客户端应用程序的连接,客户端应用程序将通过其TidTCPServer组件接收连接。 This would be a possible solution but keep in mind that generally clients are dynamic and ever changing while servers are usually static and as such it will be a mission to keep track of where clients are. 这可能是一种可能的解决方案,但要记住,通常客户端是动态的,而且不断变化,而服务器通常是静态的,因此跟踪客户端的位置是一项任务。 Too many headaches and too much work as well. 太多的头痛和太多的工作。

So I think it is better to have clients keep track of their rarely changing servers and as such it is better to have a TidTCPServer component for the server app and have it wait for client connections before it starts to send messages. 因此,我认为最好让客户端跟踪他们很少更改的服务器,因此最好为服务器应用程序安装一个TidTCPServer组件,并让它在开始发送消息之前等待客户端连接。

So to implement; 所以要实施; your clients would have to constantly try to connect to the server at regular intervals until it finds the server. 您的客户必须不断尝试定期连接到服务器,直到找到服务器。 The server can then send as many messages as it wants until asked to stop or until premature disconnect in which case the cycle will be restarted. 然后,服务器可以发送任意数量的消息,直到被要求停止或直到过早断开,在这种情况下,循环将重新启动。 There are ways in Indy to keep track of client connections and you can keep an internal list of the clients through those means. Indy有一些方法可以跟踪客户端连接,您可以通过这些方式保留客户端的内部列表。 This makes more sense. 这更有意义。 It is the way that most client-server apps work. 这是大多数客户端 - 服务器应用程序的工作方式。 Just think of Skype and any Web Server. 想想Skype和任何Web服务器。 The clients contacts the server and receives data if needs be. 客户端联系服务器并在需要时接收数据。

At the server side: 在服务器端:

  • Create the TidTCPServer object. 创建TidTCPServer对象。
  • Setup the TidTCPServer to listen on one or more of its local IP Addresses and choose an IP port for them. 设置TidTCPServer以侦听其一个或多个本地IP地址并为其选择IP端口。
  • Assign code to the TidTCPServer which it will run as soon as a client connects to it via the OnExecute of the TidTCPServer. 将代码分配给TidTCPServer,一旦客户端通过TidTCPServer的OnExecute连接它,它就会运行。 In this code you will send the messages to the connected client. 在此代码中,您将把消息发送到连接的客户端。
  • Activate the TidTCPServer so that it is in Listening mode. 激活TidTCPServer以使其处于侦听模式。

At the client side: 在客户端:

  • Create a TidTCPClient object. 创建一个TidTCPClient对象。
  • Setup the TidTCPClient to use a specific host and port (The IP Address/Host Name of the server and the port you chose) 设置TidTCPClient以使用特定主机和端口(服务器的IP地址/主机名和您选择的端口)
  • In a repeating loop with intervals try to connect to the server. 在具有间隔的重复循环中尝试连接到服务器。
  • As soon as the connection is established the client may send the server something or immediatelly try to read from the connection which is what it will receive if the server sends something 一旦建立连接,客户端就可以向服务器发送一些信息,或者立即尝试从连接中读取服务器发送的内容

There are many examples for this type of operation. 这种类型的操作有很多例子。 You must try first and if you struggle you can always ask questions specific to the problem you are having. 你必须先尝试,如果你挣扎,你总能提出具体问题的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 与TIdTCPServer同时发送和接收 - Send and receive simultaneously with TIdTCPServer 客户端断开连接后,Indy服务器TIdTCPServer.OnExecute连续调用 - Indy server TIdTCPServer.OnExecute called continuously after client disconnect 如何在已经运行的线程中运行代码以安全地发送/接收数据 [TidTCPServer] - How to run code in already running thread to safely send/recv data [TidTCPServer] 如何在TIdTcpClient和TIdTcpServer之间建立简单的连接以将字符串从客户端发送到服务器? - How to set up a simple connection between TIdTcpClient and TIdTcpServer to send a string from client to server? ¿我如何从tidtcpclient和tidtcpserver发送和接收字符串并创建聊天? - ¿How can I send and recieve strings from tidtcpclient and tidtcpserver and to create a chat? 如何在 TIdTCPServer OnExecute 中同步线程 - How to synchronize thread in TIdTCPServer OnExecute 如何使用Indy TIdTCPServer跟踪客户端数量 - How to track number of clients with Indy TIdTCPServer 如何在Android / IOS上将TIdTCPClient连接到TIdTCPServer? - How to connect TIdTCPClient to TIdTCPServer on Android/IOS? 如何使用TIdTCPServer断开非活动客户端? - how do I disconnect inactive clients with TIdTCPServer? 重新连接客户端后,TIdTCPServer无法发送数据 - TIdTCPServer not able to send data after re-connection of client
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM