TIdTCPServer OnExecute在无限循环中运行

时间:2014-01-15 22:54:32

标签: delphi indy

我遇到了TIdTCPServer组件的问题。我用它来读取远程服务器发送的数据。

以下是我使用的代码:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
const
  START_PACKET = #11;
  END_PACKET = #10;
var
  IO : TIdIOHandler;
  c  : Char;
  a  : AnsiString;
begin
  a := '';
  IO := AContext.Connection.IOHandler;

  while (IO.InputBuffer.Size > 0) do
  begin
    c := IO.ReadChar;

    if c = START_PACKET then
    begin
      repeat
        c := IO.ReadChar; //(TEncoding.ASCII);
        a := a + c;
      until (c = END_PACKET) or (IO.InputBufferIsEmpty);
    end;
  end;

  if a <> '' then
  begin
    //let's send replay to server
    IO.Write(CreateReply(a));

    //now we need to save what we received to database
    //I use critical section
    try
      EnterCriticalSection(LockDB);

      with DataModule2.results do
      begin
        Close;
        Params[0].AsDateTime := Today;
        Params[1].AsString := a;
        ExecSQL;
      end;
    finally
      LeaveCriticalSection(LockDB);
    end;
  end;
end;

问题是,一旦我的TIdTCPServer获取了一些数据,它就会启动一个无限循环并占用100%的CPU。

我在这里做错了什么?

1 个答案:

答案 0 :(得分:2)

一个问题是,您实际上从未读过任何数据,因此InputBuffer将始终为空,a将始终为空。 OnExecute事件本身是循环的,因此您没有做任何事情来使它定期产生CPU时间片。

另一个问题是你的char-by-char读取和连接效率非常低,而且没有考虑到Delphi 2009+中SizeOf(Char)为2或者ReadChar()是Unicode-察觉。

请改为尝试:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
const
  START_PACKET = #11;
  END_PACKET = #10;
var
  IO : TIdIOHandler;
  a, buf : AnsiString;
  buflen : Integer;
  c : AnsiChar;
begin
  a := '';
  IO := AContext.Connection.IOHandler;

  IO.WaitFor(START_PACKET);

  // this is just one example of how to append characters using
  // buffering. use whatever is more comfortable for you...

  SetLength(buf, 1024);
  buflen := 0;

  repeat
    c := AnsiChar(IO.ReadByte);
    if buflen = Length(buf) then
    begin
      a := a + buf;
      buflen := 0;
    end;
    buf[buflen+1] := c;
    Inc(buflen);
  until (c = END_PACKET) or (IO.InputBufferIsEmpty);

  if buflen > 0 then
  begin
    SetLength(buf, buflen);
    a := a + buf;
  end;
  buf := '';

  //let's send replay to server
  IO.Write(CreateReply(a));

  //now we need to save what we received to database
  //I use critical section
  EnterCriticalSection(LockDB);
  try
    with DataModule2.results do
    begin
      Close;
      Params[0].AsDateTime := Today;
      Params[1].AsString := a;
      ExecSQL;
    end;
  finally
    LeaveCriticalSection(LockDB);
  end;
end;

可替换地:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
const
  START_PACKET = #11;
  END_PACKET = $#10;
var
  IO : TIdIOHandler;
  a : AnsiString;
  c : AnsiChar;
  i : Integer;
begin
  IO := AContext.Connection.IOHandler;

  IO.WaitFor(START_PACKET);

  if IO.InputBufferIsEmpty then
  begin
    IO.CheckForDataOnSource(IdTimeoutDefault);
    IO.CheckForDisconnect;
  end;

  i := IO.InputBuffer.IndexOf(END_PACKET);
  if i = -1 then i := IO.InputBuffer.Size;

  a := IO.ReadString(i);

  if a <> '' then
  begin
    //let's send replay to server
    IO.Write(CreateReply(a));

    //now we need to save what we received to database
    //I use critical section
    EnterCriticalSection(LockDB);
    try
      with DataModule2.results do
      begin
        Close;
        Params[0].AsDateTime := Today;
        Params[1].AsString := a;
        ExecSQL;
      end;
    finally
      LeaveCriticalSection(LockDB);
    end;
  end;
end;