Delphi 在读取OneExecute事件中的所有数据之前,什么可能导致IdTCPServer失败?

Delphi 在读取OneExecute事件中的所有数据之前,什么可能导致IdTCPServer失败?,delphi,tcp,indy,Delphi,Tcp,Indy,当我使用Indy客户端组件通过LAN发送数据时,该代码工作正常,但当我从web接收外部应用程序的数据时,它会导致数据失败。在读取所有数据之前,客户端是否会导致IdTCPServer断开连接?客户端平均发送33000个字符。有什么建议吗 procedure TFrmMain.IdTCPServer1Execute(AContext: TIdContext); var strm: TMemoryStream; RxBuf: TIdBytes; begin Memo1.Clear; s

当我使用Indy客户端组件通过LAN发送数据时,该代码工作正常,但当我从web接收外部应用程序的数据时,它会导致数据失败。在读取所有数据之前,客户端是否会导致IdTCPServer断开连接?客户端平均发送33000个字符。有什么建议吗

procedure TFrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
  strm: TMemoryStream;
  RxBuf: TIdBytes;
begin
  Memo1.Clear;
  strm := TMemoryStream.Create;
  try
    // read until disconnected
    AContext.Connection.IOHandler.ReadStream(strm, -1, true);
    strm.Position := 0;
    ReadTIdBytesFromStream(strm, RxBuf, strm.Size);
  finally
    strm.Free;
  end;
  Memo1.Lines.Add(BytesToString(RxBuf));
  AContext.Connection.IOHandler.WriteLn('000');
end;
我还尝试了另一个代码,与第一个代码不同,它只读取发送的部分数据。有没有办法让IdTCPServer处理程序等待所有数据收集完毕

procedure TFrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
  RxBuf: TIdBytes;
begin
  RxBuf := nil;
  with AContext.Connection.IOHandler do
  begin
    CheckForDataOnSource(10);
    if not InputBufferIsEmpty then
    begin
      InputBuffer.ExtractToBytes(RxBuf);
    end;
  end;
  AContext.Connection.IOHandler.WriteLn('000');
  Memo1.Lines.Add( BytesToString(RxBuf) );
end;



为了进一步参考任何人,我必须创建一个循环并等待客户端发送EOT chr(4),以便收集IdTCPServer1Execute上的所有数据。这是因为数据被Indy分割,代码如下所示:

procedure TFrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
  Len: Integer;
  Loop: Boolean;
begin
  CoInitialize(nil);
  cdsSurescripts.Close;
  Loop := True;
  while Loop = true do
  begin
    if AContext.Connection.IOHandler.Readable then
    begin
      AContext.Connection.IOHandler.ReadBytes( RxBuf,-1, True);
      Len := Length(BytesToString(RxBuf));
      if Copy(BytesToString(RxBuf), Len, 1) =  '' then
      begin
        loop := False;
      end;
    end;
  end;
  Display('CLIENT', BytesToString(RxBuf));
  AContext.Connection.IOHandler.WriteLn('000');
  CoUninitialize();
end;

你作为答案发布的代码完全错误

首先,您不能在任意字节块上使用
BytesToString()
,这将无法正确处理UTF-8等多字节编码

此外,您没有正确查找EOT终止符。如果客户端发送多条XML消息,则不能保证每次读取后它将是
RxBuf
的最后一个字节。即使是这样,使用
Copy(BytesToString(),…)
将其提取到
字符串中,也不会像代码所期望的那样产生空字符串

如果客户端在XML末尾发送EOT终止符,则不需要手动读取循环。只需使用EOT终止符调用
TIdIOHandler.ReadLn()
,并让它在内部处理读取循环,直到到达EOT为止

另外,
CoInitialize()
CoUninitialize()
调用应该分别在
OnConnect
OnDisconnect
事件中完成(实际上,最好在分配给
TIdSchedulerOfThread.ThreadClass
属性的
TIdThreadWithTask
子代中调用它们,但这是下一次更高级的主题)

尝试类似以下内容:

procedure TFrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
  Len: Integer;
  Loop: Boolean;
begin
  CoInitialize(nil);
  cdsSurescripts.Close;
  Loop := True;
  while Loop = true do
  begin
    if AContext.Connection.IOHandler.Readable then
    begin
      AContext.Connection.IOHandler.ReadBytes( RxBuf,-1, True);
      Len := Length(BytesToString(RxBuf));
      if Copy(BytesToString(RxBuf), Len, 1) =  '' then
      begin
        loop := False;
      end;
    end;
  end;
  Display('CLIENT', BytesToString(RxBuf));
  AContext.Connection.IOHandler.WriteLn('000');
  CoUninitialize();
end;
过程TFrmMain.IdTCPServer1Connect(AContext:TIdContext);
开始
共初始化(零);
AContext.Connection.IOHandler.DefStringEncoding:=IndyTextEncoding\u UTF8;
结束;
过程TFrmMain.IdTCPServer1Disconnect(AContext:TIdContext);
开始
coninitialize();
结束;
过程TFrmMain.IdTCPServer1Execute(AContext:TIdContext);
变量
XML:string;
开始
CDS说明。关闭;
XML:=AContext.Connection.IOHandler.ReadLn(#4);
显示('CLIENT',XML);
AContext.Connection.IOHandler.WriteLn('000');
结束;

就个人而言,我会采取另一种方法。我建议使用支持推送模型的XML解析器。然后您可以从连接中读取任意字节块并将它们推送到解析器中,让它为完成的XML元素向您触发事件,直到到达终止符。这样,您就不必浪费时间和内存或者先在内存中缓冲整个XML,然后再处理它。

…这是导致它失败的原因。
这是什么意思?你观察到什么导致了这个“失败”的结论?如果使用
AContext.Connection.IOHandler.ReadStream(strm,0,true)会发生什么
?OneExecute事件在工作线程中运行,而不是在主UI线程中运行。您在不同步的情况下使用TMemo不是线程安全的。此外,如果要在断开连接之前读取客户端的所有数据,则以后调用WriteLn是没有意义的,因为客户端将永远无法获取它。根据数据的性质,readi在使用之前将所有数据放入一个大内存缓冲区可能太浪费了。数据实际上是什么样子的?当我说失败时,我会进行跟踪,当它在这一行时:AContext.Connection.IOHandler.ReadStream(strm,-1,true);它跳转到最后一个异常。@user734781
…它跳转到最后一个异常
。因此…捕获异常并告诉我们它是什么。这个代码都错了。请参阅我刚才发布的答案。