为什么我在Indy套接字9 IdTcpServer ServerExecute中获得AccessViolation?

时间:2009-06-19 08:56:08

标签: delphi tcp indy access-violation

第一个问题:

以下例程是Indy 9 IdTcpServer.OnExecute例程的正确实现吗?

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;

第二个(实际上更重要)问题:

现在偶尔会出现访问冲突(从地址000000读取)。显然在行:

  AContext.Connection.ReadFromStack(True, 600, False);

但是检查AContext / Connection / InputBuffer / IOHandler = nil BEFORE是否为false。 在调用之后(以及在引发异常之后),IOHandler为零。

我们正在使用RAD Studio / Delphi 2007。

3 个答案:

答案 0 :(得分:0)

嗯,我拥有的最简单的onExecute处理程序是这样的。 (原谅C ++而不是Delphi,但你会明白的。

void __fastcall MyPanel::DoTCPExecute(TIdPeerThread * AThread)
{
  AnsiString text =AThread->Connection->ReadLn();
  // now do something with text
}

我能看到的唯一明显的问题是你正在尝试使用数据的“时间”来确定何时有一个完整的字符串。这是TCP的真正禁忌。您可能只是拥有字符串的第一个字节,或者您可能同时拥有多个字符串。使用TCP,无法保证每个“发送”最终都会在另一端作为单个“接收”。

您需要以其他方式“分隔”您的字符串。 Readln使用换行符作为终止符 - 另一种方法是使用长度字段为每个数据块添加前缀。你读取长度,然后读取剩余的数据。

答案 1 :(得分:0)

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

  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;

答案 2 :(得分:0)

IOHandler可以像你描述的那样成为nil的唯一方法是你的应用程序中的另一个线程在你的工作线程仍在运行时在连接上调用Disconnect()。