Delphi 为什么我在Indy Sockets 9 IdTcpServer ServerExecute中遇到访问冲突?

Delphi 为什么我在Indy Sockets 9 IdTcpServer ServerExecute中遇到访问冲突?,delphi,tcp,indy,access-violation,Delphi,Tcp,Indy,Access Violation,第一个问题: 以下例程是否是Indy 9 IdTcpServer.OneExecute例程的正确实现 procedure TMyConnServer.ServerExecute(AContext: TIdPeerThread); var buffSize: integer; str: string; begin AContext.Connection.ReadFromStack(True, 600, False); buffSize := AContext.Connec

第一个问题:

以下例程是否是Indy 9 IdTcpServer.OneExecute例程的正确实现

procedure TMyConnServer.ServerExecute(AContext: TIdPeerThread);
var
  buffSize: integer;
  str:      string;
begin
  AContext.Connection.ReadFromStack(True, 600, False);
  buffSize := AContext.Connection.InputBuffer.Size;
  if (buffSize > 0) then
    { Extract input buffer as string }
    str := AContext.Connection.ReadString(buffSize);

    { Notify connection object of received data }
    if (AContext.Data <> nil) then
    begin
      TConnectionHandler(AContext.Data).Read(str);
    end;
  end;
end;
但是检查AContext/Connection/InputBuffer/IOHandler=nil BEFORE是否为false。 调用之后以及引发异常之后,IOHandler为nil


我们使用的是RAD Studio/Delphi 2007。

我拥有的最简单的onExecute处理程序如下所示。原谅C++而不是德尔福,但你会明白的。
void __fastcall MyPanel::DoTCPExecute(TIdPeerThread * AThread)
{
  AnsiString text =AThread->Connection->ReadLn();
  // now do something with text
}
我能看到的唯一明显的问题是,您试图使用数据的计时来确定何时有一个完整的字符串。这对TCP来说是一个真正的禁忌。您可能只有字符串的第一个字节,或者可能同时发送多个字符串。使用TCP,无法保证每次发送都会在另一端作为单个接收结束


你需要用另一种方式来划分你的字符串。Readln使用换行符作为终止符-另一种方法是在每个数据块前面加上长度字段。读取长度,然后读取剩余数据。

代码就是这样工作的,但我认为这不是一个干净的选项:

  if (AContext.Connection.Connected) then
  begin
    try
      AContext.Connection.ReadFromStack(false, 1, false);
    except on E: EAccessViolation do
      // ignore
    end;
  end; 
  buffSize := AContext.Connection.InputBuffer.Size;

IOHandler变为零的唯一方法是,如果应用程序中的另一个线程在连接上调用Disconnect,而您的工作线程仍在运行。

您好,恐怕ReadLn没有选项,因为数据没有换行分隔符。我知道数据可能不完整,通常也不完整,但重建是在.Readstr方法的后面完成的。实际上,数据类型“string”只是用来传输原始字节,因为这就是我们以后需要数据的方式。除此之外,ReadLn还可以在内部调用ReadFromStack,这将再次导致EACCESS冲突……如果数据具有任何类型的分隔符,您可以将该分隔符传递给ReadLn,它不仅限于CR/LF字符。如果数据是以另一种方式分隔的,例如通过前面的标题来指定如何读取其余数据,那么您必须单独处理该数据。使用字符串作为原始字节缓冲区不是一个好主意,尤其是当您升级到D2009时,在D2009中,字符串行为已经改变。如果需要对原始字节进行操作,则使用实际的原始字节缓冲区,例如TBytes。Indy有读取/写入原始字节的方法。嗯,是的,我想这是正确的。既然ServerExecute函数不重叠,它们会重叠吗?我可以只使用一个CriticalSection并在ServerExecute内锁定,在断开连接时也锁定吗?TIdTCPServer是一个多线程组件。每个客户端连接都在自己的线程中运行。因此,OnExecute事件处理程序可以同时运行多次,每次都在不同的线程上下文中运行。您不需要锁定对服务器各个客户端连接的访问,除非您需要在多个线程中读取这些连接,或者在多个线程中写入它们,这通常意味着您可能有一个糟糕的代码设计。Indy在内部为您处理连接的调用。Connected返回True,即使套接字可能已经关闭,但如果InputBuffer中仍有未读数据,这是设计的。您应该去掉对Connected的调用以及异常处理程序,以便TIdTCPServer可以为您处理正确套接字管理所必需的错误。只需正常调用ReadFromStack,并让它报告所需的任何错误。
  if (AContext.Connection.Connected) then
  begin
    try
      AContext.Connection.ReadFromStack(false, 1, false);
    except on E: EAccessViolation do
      // ignore
    end;
  end; 
  buffSize := AContext.Connection.InputBuffer.Size;