【问题标题】:Indy TIdTCPServer TIdTCPClient data exchangeIndy TIdTCPServer TIdTCPClient 数据交换
【发布时间】:2014-06-12 12:57:14
【问题描述】:

我花了一些时间编写一个简单的应用程序来在TIdTCPServer 和TIdTCPClient 之间交换数据。但现在我被困住了。
我可以将数据从TIdTCPClient 发送到TIdTCPServer 并且可以处理。
但是不知道,官方文档没有提供任何线索如何从TIdTCPServer 发送数据并在TIdTCPClient 上处理它。请指教。

我的代码很简单:

主要应用:

var
  Form1: TForm1;

implementation

uses ClientThread, ServerThread;

var
  ClientThread: TClientThread;
  ServerThread: TServerThread;

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
var OutputDebugString:string;
begin
  ServerThread:=TServerThread.Create(False);
  ServerThread.Priority:=tpNormal;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ClientThread:=TClientThread.Create(False);
  ClientThread.Priority:=tpNormal;
 end;

服务器线程:

unit ServerThread;

interface

uses
  Classes, System.SysUtils, IdContext, IdTCPServer, TaskQue;

type
  TServerThread = class(TThread) //MyThread - заданное нами имя потока.
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

 TServer = class(TObject)
   IdTCPServer1: TIdTCPServer;
   procedure IdTCPServer1Execute(AContext: TIdContext);
   procedure IdTCPServer1Connect(AContext: TIdContext);
  private
   { Private declarations }
   constructor Create;
  public
  end;

type
TDatagram = record
    Proto: byte;
    Command: word;
    DataSize: word;
    data: array [0..4096] of byte;
  end;

var
  Server : TServer;

implementation

uses YouFreedom;

constructor TServer.Create;
begin
 inherited Create;
 IdTCPServer1 := TIdTCPServer.Create(nil);
 IdTCPServer1.Bindings.Clear;
// IdTCPServer1.DefaultPort := 10001;
  try
    with idTCPserver1.Bindings.Add do
    begin
      IP := '127.0.0.1';
      Port := 10001;
    end;
  finally     //dirty hack
      idTCPserver1.Bindings.Add.IP := '127.0.0.1';
      idTCPserver1.Bindings.Add.Port := 10002;
  end;
// idTCPserver1.Bindings.Add.Port:=10001;
// IdTCPServer1.Bindings.Add.IP := '127.0.0.1';
 IdTCPServer1.Tag := 0;
 IdTCPServer1.TerminateWaitTime := 5000;
 IdTCPServer1.OnConnect := IdTCPServer1Connect;
 IdTCPServer1.OnExecute := IdTCPServer1Execute;
end;

procedure TServer.IdTCPServer1Execute(AContext: TIdContext);

var
  MIRec: TDatagram;
  msRecInfo: TMemoryStream;
  size: integer;
  i:integer;
  recieve:byte;
  respstream: TMemoryStream;
begin
  try
   msRecInfo:= TMemoryStream.Create;
   AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, false);
   msRecInfo.Position := 0;
   msRecInfo.ReadBuffer(MIRec, msRecInfo.size);
   Form1.addtoque := '1';
//   Form1.s := inttostr(MIRec.Proto)
  Form1.Memo1.Lines.Add('Proto = ' + inttostr(MIRec.Proto));
  finally
   msRecInfo.Free
  end;
end;

procedure TServer.IdTCPServer1Connect(AContext: TIdContext);
begin
//AContext.Connection.Socket.WriteLn('hello');
end;

procedure TServerThread.Execute;
begin
 Server := TServer.Create;
 try
  Server.IdTCPServer1.Active := True;
 except
      on E: Exception do
       // OutputDebugString(PChar(E.ToString)); //do something
      end;
end;


end.

客户端线程:

unit ClientThread;

interface

uses
  Classes, IdTCPClient;

type
  TClientThread = class(TThread) //MyThread - заданное нами имя потока.
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

 TClient = class(TObject)
   IdTCPClient1: TIdTCPClient;
//   procedure IdTCPClient1OnWorkBegin(AContext: TIdContext);
  private
   { Private declarations }
   constructor Create;
  public
  end;

implementation

type
TDatagram = record
    Proto: byte;
    Command: word;
    DataSize: word;
    data: array [0..4096] of byte;
  end;

var
  ClientConnection : TClient;

constructor TClient.Create;
begin
 inherited Create;
 IdTCPClient1 := TIdTCPClient.Create(nil);
// IdTCPClient1.ReuseSocket := rsOSDependent;
 IdTCPClient1.Host := '127.0.0.1';
 IdTCPClient1.Port := 10001;
// IdTCPClient1.OnWorkBegin := IdTCPClient1OnWorkBegin;
end;

procedure TClientThread.Execute;
var
  MIRec: TDatagram;
  msRecInfo: TMemoryStream;
  i,k:integer;
  Client1: TIdTCPClient;
  recieve:byte;
  respstream: TMemoryStream;
begin
  ClientConnection := TClient.Create;
  ClientConnection.IdTCPClient1.Connect;
  for k := 1 to 5 do begin

  if ClientConnection.IdTCPClient1.Connected then begin
{   MIRec.DataSize := 64;
   for i:=0 to MIRec.DataSize do
    MIRec.data[i] := i;
   for i:=129 to 4096 do MIRec.data[i] := 0;}
   MIRec.Proto := 1;
   MIRec.Command :=1;
  try
    msRecInfo := TMemoryStream.Create;
    msRecInfo.WriteBuffer(MIRec, SizeOf(MIRec));
    msRecInfo.Position := 0;
    ClientConnection.IdTCPClient1.IOHandler.Write(msRecInfo, msRecInfo.Size, true);
  finally
    msRecInfo.Free;
  end;
  end;
  end
 end;




end.

【问题讨论】:

    标签: delphi indy


    【解决方案1】:

    您在滥用Bindings.Add(),因此正在创建 3 绑定:

    127.0.0.1:10001
    127.0.0.1:0
    0.0.0.0:10002
    

    我确定这不是你真正想要的。

    至于您的问题 - 这取决于您的服务器需要做什么。

    如果服务器仅响应客户端命令,那么您可以在读取命令后直接在OnExecute 事件中写入响应。客户端可以在发送命令后立即读取响应。这是典型的用法。

    如果服务器只向客户端发送未经请求的数据,那么你可以在需要时Lock()服务器的Contexts列表,找到所需的连接并写入它,然后Unlock()列表.客户端必须异步读取,例如在线程中读取这些消息。

    如果服务器需要两者,那么这会变得很棘手。最好的选择是为每个客户端实现一个线程安全的出站队列,然后您可以将未经请求的数据放入队列,并在安全的情况下让OnExecute 发送队列的内容。

    我之前曾多次在 Embarcadero 和 Indy 论坛上发布所有这些示例。到处搜索。

    【讨论】:

    • 这段代码只是一个原型,所以我没有过多关注安全和资源管理。你是对的,最后我想要一个以异步方式回答客户的问题。并坚持服务器和客户端的事件以将数据发送回客户端。但是我会尝试搜索。
    猜你喜欢
    • 2022-01-23
    • 2019-07-01
    • 2021-04-06
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多