繁体   English   中英

TIdTCPServer OnExecute在无限循环中运行

[英]TIdTCPServer OnExecute runs in an infinite loop

我遇到了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。

我在这做错了什么?

一个问题是,你是永远不会实际读取任何数据,因此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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM