【问题标题】:How IdTCPServer can send and receive answer from specific client using OnExecuteIdTCPServer 如何使用 OnExecute 发送和接收来自特定客户端的应答
【发布时间】:2015-02-21 02:34:52
【问题描述】:

几周前我开始使用 Indy TCPServer 和 TCPClient,现在,经过 SOF 专家(特别是 Lebeau 先生)的大量研究和帮助,我可以安全地管理客户端连接并向特定客户端发送字符串消息。这是一段代码:

type
  TClient = class(TObject)
  private
    FHost: string;                  
  public
    FQMsg: TIdThreadSafeStringList; // Message Queue
    constructor Create(const Host: string);
    destructor Destroy; override;
  end;

procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
  Client: TClient;
  LQueue: TStringList;
  WQueue: TStringList;
begin
  with AContext.Connection.IOHandler Do
  begin
    DefStringEncoding := TEncoding.UTF8;
    LQueue := nil;
    Client := TClient(AContext.Data);
    try
      WQueue := Client.FQMsg.Lock;
      try
        if (WQueue.Count > 0) then
        begin
          LQueue := TStringList.Create;
          LQueue.Assign(WQueue);
          WQueue.Clear;
        end;
      finally
        Client.FQMsg.Unlock;
      end;
      if (LQueue <> nil) then
        Write(LQueue);
    finally
      LQueue.Free;
    end;
  end;
end;

现在是时候更进一步,尝试从客户那里得到答复。但是突然间我意识到我不能使用 TCPServer 的 OnExecute 事件来“同时”发送消息和接收答案??我可能错了,但这段代码不起作用,我不知道为什么......

procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
  RStr: string;
  Client: TClient;
  LQueue: TStringList;
  WQueue: TStringList;
begin
  with AContext.Connection.IOHandler Do
  begin
    DefStringEncoding := TEncoding.UTF8;
    // Send Cmd
    LQueue := nil;
    Client := TClient(AContext.Data);
    try
      WQueue := Client.FQMsg.Lock;
      try
        if (WQueue.Count > 0) then
        begin
          LQueue := TStringList.Create;
          LQueue.Assign(WQueue);
          WQueue.Clear;
        end;
      finally
        Client.FQMsg.Unlock;
      end;
      if (LQueue <> nil) then
        Write(LQueue);
    finally
      LQueue.Free;
    end;
    // Receive Data
    RStr := Trim(ReadLn);
    if (RStr <> '') then
    begin
      SyncLog(RStr);
    end;
  end;
end;

当我将最后一部分 (ReadLn) 添加在一起时,代码的第一部分不起作用,我无法再向客户端发送消息:(

拜托,有人知道我错过了什么吗?

谢谢!

【问题讨论】:

    标签: delphi tcp indy


    【解决方案1】:

    首先,使用TIdTextEncoding.UTF8 代替TEncoding.UTF8(如果升级到Indy 10.6+,则使用IndyTextEncoding_UTF8),并将DefStringEncoding 的分配移动到OnConnect 事件。你只需要分配一次,而不是每次读/写。

    其次,ReadLn() 是一种阻塞方法。它会退出直到实际读取一行,或者发生超时/错误。因此,要执行您正在尝试的操作,您必须在实际读取数据之前检查是否存在入站数据,以便您可以超时并退出并让OnExecute 循环返回以再次检查队列。

    试试这样的:

    type
      TClient = class(TObject)
      private
        FHost: string;                  
        FQMsg: TIdThreadSafeStringList; // Message Queue
      public
        constructor Create(const Host: string);
        destructor Destroy; override;
        property QMsg: TIdThreadSafeStringList read FQMsg;
      end;
    
    procedure TfrmMain.TCPServerConnect(AContext: TIdContext);
    var
      Client: TClient;
    begin
      AContext.Connection.IOHandler.DefStringEncoding := TIdTextEncoding.UTF8;
      ...
      Client := TClient.Create;
      ...
      AContext.Data := Client;
      ...
     end;
    
    procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
    var
      RStr: string;
      Client: TClient;
      LQueue: TStringList;
      WQueue: TStringList;
    begin
      Client := TClient(AContext.Data);
      // Send Cmd
      LQueue := nil;
      try
        WQueue := Client.QMsg.Lock;
        try
          if (WQueue.Count > 0) then
          begin
            LQueue := TStringList.Create;
            LQueue.Assign(WQueue);
            WQueue.Clear;
          end;
        finally
          Client.QMsg.Unlock;
        end;
        if (LQueue <> nil) then
          AContext.Connection.IOHandler.Write(LQueue);
      finally
        LQueue.Free;
      end;
      // Receive Data
      if AContext.Connection.IOHandler.InputBufferIsEmpty then
      begin
        if not AContext.Connection.IOHandler.CheckForDataOnSource(100) then Exit;
        AContext.Connection.IOHandler.CheckForDisconnect;
      end;
      RStr := Trim(AContext.Connection.IOHandler.ReadLn);
      if (RStr <> '') then
      begin
        SyncLog(RStr);
      end;
    end;
    

    【讨论】:

    • 工作就像一个魅力!再次感谢 Lebeau 先生!现在是我尝试理解您的解释和代码的时候了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    • 2019-08-25
    • 2020-03-06
    • 1970-01-01
    • 2015-01-16
    • 2017-05-13
    相关资源
    最近更新 更多