【问题标题】:Use TCPServer to ask TCPClient for a stream with Delphi使用 TCPServer 向 TCPClient 询问 Delphi 的流
【发布时间】:2015-01-02 22:28:33
【问题描述】:

我又来了……现在我正在尝试玩流媒体。我的目标是使用 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;

请问,我做错了什么?

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

【问题讨论】:

  • @预期结果是什么?相反会发生什么?有任何错误信息吗?数据已收到但已损坏?您需要让我们更多地了解这并不能满足您的需求。
  • @JerryDodge,这是一个奇怪的行为,服务器收到流时断开连接......预期的结果是接收文件并保存。

标签: delphi tcp stream indy


【解决方案1】:

在服务器端,如果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;

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

【讨论】:

  • 再次感谢@RemyLebeau!首先,我正在一步一步地了解它是如何工作的。然后,我将尝试将所有人团结在一起。但不幸的是你的代码没有工作...... ReadStream(Stream, -1) 是空的并且“中止” OnExecute (好吧,我真的不明白发生了什么)......请,还有其他提示吗?谢谢!
  • 操作,抱歉,现在成功了!在我的测试中,我错误地将“Write(Stream, 0, True)”更改为“Write(Stream, 0, False)”。但现在正在工作!谢谢!!再次,我将分析代码,进行测试以更好地理解,然后进入下一步...... Lebeau 先生,我希望您在 2015 年取得更多成功!
猜你喜欢
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 2013-09-03
  • 1970-01-01
相关资源
最近更新 更多