【问题标题】:Delphi Rio 10.3.3 with Indy 10.6.2.5366 TIdTCPServer thread problemDelphi Rio 10.3.3 with Indy 10.6.2.5366 TIdTCPServer 线程问题
【发布时间】:2020-03-31 14:39:55
【问题描述】:

我正在使用 Windows 10 1903、Delphi Rio 10.3.3 和 Indy 10.6.2.5366。

我正在将使用 TServerSocket 的旧 Windows 服务应用程序升级到 Indys TIdTCPServer。主要原因是我必须为应用程序添加 IPv6 支持。

我遇到的问题是 TIdTCPServer 吃线程。对于到 TIdTCPServer 的每个连接,都会分配一个新线程(应该如此),但是当客户端断开连接时,线程不会关闭。

如果我同时连接两个客户端,则 IdTCPServer1.Contexts.LockList.Count = 2 并且 OnExecute 事件会在每个“周期”被触发两次。如果我然后断开一个客户端以便 IdTCPServer1.Contexts.LockList.Count = 1,则 OnExecute 每个周期仅触发一次(也应该如此),但两个线程仍在运行。 (我用windows任务管理器看这个)

我构建了一个简单的测试应用程序,它以几秒钟的间隔随机连接和断开连接,启动了 5 个程序,当达到大约 150 个线程时,我的服务崩溃了。

这是我的 OnExecute 事件:

procedure T#############.IdTCPServer1Execute(AContext: TIdContext);
var
 incomestring: string;
begin
 try
   if AContext.Connection.IOHandler.InputBufferIsEmpty then
   begin
    AContext.Connection.IOHandler.CheckForDataOnSource(100);
    AContext.Connection.IOHandler.CheckForDisconnect;
    if AContext.Connection.IOHandler.InputBufferIsEmpty then
     Exit;
   end;

   incomestring:= AContext.Connection.IOHandler.InputBufferAsString(en8bit);

   if length(trim(incomestring)) = 0 then
   begin
    exit;
   end;

   DataRead(incomestring, AContext); // Send data be processed
  except
   on E: Exception do
   begin
    if E is EIdException then
     raise // <- re-raise only Indy-specific exceptions end;
    else
    begin
     inc(ErrorCount);
     Logg('Error in IdTCPServer1Execute: ' + E.Message, ltError, AContext);
    end;
   end;
 end;
end;

我使用 InputBufferAsString 的原因是我无法控制连接到服务器的客户端。所以最后并不总是有 CR 或 LF(正如 ReadLn 所希望的那样)。而且客户端在断开连接之前会与服务器保持连接数小时。

【问题讨论】:

  • 您真的觉得有必要审查表单名称吗?你能做的最好的事情是T#### 而不是默认的TForm1?
  • 这可能是线程池的问题。当线程数接近 150 时,真的没有理由崩溃,除非您的系统资源不足。我认为您的问题出在其他地方。
  • 您好,您是否尝试使用连接的 ReadTimeout 属性?
  • 默认情况下,Indy 不使用线程池。您必须通过将TIdSchedulerOfThreadPool 分配给TIdTCPServer.Scheduler 来显式启用它,否则将使用TIdSchedulerOfThreadDefault,它不会合并。但是你真的打电话给IdTCPServer1.Contexts.LockList() 吗?如果是这样,你也打电话给IdTCPServer1.Contexts.UnlockList() 吗?我在这段代码中看不到任何会导致线程无法正确终止的内容,除非DataRead()Logg() 正在阻塞线程,或者您将Contexts 锁定。所示代码之外的内容。
  • 感谢您的回复。是的,每次迭代 LockList() 时,我都会在 finally 子句中调用 UnlockList()。问题似乎出在 DataRead 过程中。我会进一步调查。

标签: multithreading delphi indy delphi-10.3-rio


【解决方案1】:

问题解决了!在我的 DataRead() 过程中,我使用 TIdContext.Data 成员来存储指向具有额外信息的类的指针。在 IdTCPServer1Disconnect 上,我释放了额外的信息类,但我忘记将 TidContext.Data 设置为 nil。

所以,如果您曾经使用过 TIdContext.Data 成员,请记住在完成后将其设置为 nil!否则线程将永远持续下去。

【讨论】:

    猜你喜欢
    • 2020-06-01
    • 2021-06-12
    • 1970-01-01
    • 2020-08-21
    • 2014-05-29
    • 1970-01-01
    • 2012-07-12
    • 2012-07-29
    • 2011-08-16
    相关资源
    最近更新 更多