使用 TCPServer 向 TCPClient 请求 Delphi 的流

Use TCPServer to ask TCPClient for a stream with Delphi

我又来了...现在我正在尝试使用流。我的目标是使用 TCPServer 向 TCPClient 请求流并正确接收它。这是我正在尝试但没有成功的方法:

procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
  SCmd: string;
  Client: TClient;
  LQueue: TStringList;
  WQueue: TStringList;
  Stream: TMemoryStream;
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
    begin
      SCmd := LQueue[0];
      AContext.Connection.IOHandler.Write(SCmd);
    end;
  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;
  if (SCmd = 'sendfile') then
  begin
    Stream := TMemoryStream.Create;
    try
      AContext.Connection.IOHandler.ReadStream(Stream, -1);
      Stream.Position := 0;
      Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
    finally
       Stream.Free;
    end;
  end;
end;

在客户端,我创建了一个线程来监听和处理命令。这是代码:

procedure TClientProc.Execute;
begin
  TCPClient := TIdTCPClient.Create(nil);
  while (not Terminated) do
  begin
    with TCPClient do
    begin
      if (Connected) then
      try
        FCmd := Trim(IOHandler.ReadLn);
        if (FCmd <> '') then Synchronize(CommandProc);
      except
      end else
      begin
        if (FCnt >= FInt) then
        try
          ConnectTimeout := 4000;
          Port := StrToInt(FPort);
          Host := FHost;
          Connect;
        except
          FCnt := 0;
        end else
        begin
         Inc(FCnt);
        end;
      end;
      Sleep(1000);
    end;
  end;
  TCPClient.Disconnect;
  TCPClient.Free;
end;

Procedure TClientProc.CommandProc;
var
  Stream: TMemoryStream;
begin
  if FCmd = 'sendfile' then
  begin
    Stream := TMemoryStream.Create;
    try
      Stream.LoadFromFile(ExtractFilePath(Application.ExeName) + 'test.zip');
      Stream.Position := 0;
      TCPClient.IOHandler.Write(Stream, 0, True);
    finally
      Stream.Free;
    end;
  end;
end;

请问我哪里做错了?

顺便说一句,新年快乐!! :)

在服务器端,如果 TClient 的队列中有多个命令,而 OnExecute 有机会检查它,那么您将丢弃除第一个命令之外的所有命令。你需要全部处理它们。

试试像这样的东西:

procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
  SCmd: string;
  Client: TClient;
  WQueue: TStringList;
  Stream: TMemoryStream;
begin
  Client := TClient(AContext.Data);
  // Send Cmd
  WQueue := Client.QMsg.Lock;
  try
    if (WQueue.Count > 0) then
    begin
      SCmd := WQueue[0];
      WQueue.Delete(0);
    end;
  finally
    Client.QMsg.Unlock;
  end;
  if (SCmd = '') then
  begin
    AContext.Connection.IOHandler.Write(SCmd);
    if (SCmd = 'sendfile') then
    begin
      Stream := TMemoryStream.Create;
      try
        AContext.Connection.IOHandler.ReadStream(Stream, -1);
        Stream.Position := 0;
        Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
      finally
        Stream.Free;
      end;
    end;
  end;
end;

当然,这只有在服务器是唯一发送命令的一方时才有效。如果客户端曾经向服务器发送命令,这将使代码更难管理,并且需要更详细的协议,因为服务器需要能够区分入站数据何时属于命令还是响应。