IdTCPServer如何使用OnExecute从特定客户端发送和接收答案

时间:2014-12-22 23:37:19

标签: delphi tcp indy

几周前我开始使用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)一起添加时,代码的第一部分不起作用,我无法再将消息发送给客户端:(

拜托,谁知道我错过了什么?

谢谢!

1 个答案:

答案 0 :(得分: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;