TIdHttpServer 在 Windows 更新后 Active 设置为 False 时冻结
Posted
技术标签:
【中文标题】TIdHttpServer 在 Windows 更新后 Active 设置为 False 时冻结【英文标题】:TIdHttpServer freezing when Active set to False after Windows Update 【发布时间】:2018-07-16 13:01:20 【问题描述】:我们有一个 Indy(版本 10.6.1.5235)TIdHttpServer“服务”,多年来一直与 Delphi 2007 一起运行良好。在最近的 Windows 更新(KB4338815 和 KB4338830)之后,我们注意到服务在 TIdHttpServer 设置为 false 时冻结。
我已经包含了创建 TIdHttpServer 的源代码。在我们的服务“停止”处理程序中,我们将 IdHttpServer1.Active 设置为 False,这就是它冻结的地方。 Indy 在尝试关闭 http 连接时似乎挂起。有解决办法吗?
更新一个 根据 Remy Lebeau,我创建了一个最小、完整且可验证的示例。这里是:
procedure TMainForm.Button1Click(Sender: TObject);
begin
memo1.clear;
iCall := 0;
IdHTTPServer1 := TIdHTTPServer.Create;
IdHTTPServer1.MaxConnections := 10;
IdHTTPServer1.AutoStartSession := True;
IdHTTPServer1.SessionState := True;
IdHTTPServer1.OnCommandGet := IdHTTPServer1CommandGet;
IdHTTPServer1.KeepAlive := False;
idHttpServer1.DefaultPort := 80;
if ReuseSocket.checked then
IDHTTPSERVER1.ReuseSocket := rsTrue;
IdHTTPServer1.Active := True;
end;
procedure TMainForm.IdHTTPServer1CommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
iCall := iCall + 1;
if iCall mod 100 = 0 then
memo1.lines.add(inttostr(iCall)+ ' calls made');
AResponseInfo.ContentText := '<html><body>Hello There</body></html';
end;
procedure TMainForm.StopClick(Sender: TObject);
begin
try
IdHTTPServer1.Active := False;
memo1.lines.add('IdHTTPServer1.Active := False;');
except
on e: exception do
memo1.lines.add('Exception on IdHTTPServer1.Active := False; Message:'+e.message);
end;
end;
应用程序可以正常运行,但是一旦您单击将 IdHttpServer Active 属性设置为 False 的“停止”按钮,它就会挂起。
【问题讨论】:
您可以尝试更新版本的 Indy 吗? (10.6.1 比较老了) 是的。下载了 Indy Version10.6.2.5464 并会让你知道结果。这是 Indy 的最新版本吗?旁注:在 indyproject.org 上有下载的地方吗?我找到了indyproject.org/Sockets/Download/Files/Indy10.EN.aspx,但似乎没有源下载。我终于从indy.fulgan.com得到它了,这是官方下载库吗? indy.fulgan.com 用于夜间快照,但您也可以直接从subversion repository 查看源代码,另请参阅indy.fulgan.com/… @MSchenkel 您没有说在您停用服务器时是否有任何活动的客户端连接。但是,您的OnCommandGet
事件处理程序不是线程安全的。 TIdHTTPServer
是一个多线程组件,它的事件是在内部工作线程的上下文中触发的,因此在访问 Form 上的 TMemo
组件时必须与主 UI 线程同步,否则会发生坏事。我建议您使用 TThread.Queue()
或 TIdNotify
来完成此操作,这样服务器就不必等待同步完成。
@MSchenkel 如果编写不正确,即使是简单的测试也会导致大问题。永远不要从 UI 线程之外访问 UI 组件。不,TCriticalSection
不会解决这个问题(尽管您可以使用它来提供对您的iCall
变量的安全访问,但至少可以考虑使用TIdThreadSafeInteger
)。 Indy 服务器在停用期间会自动为您断开活动客户端。当 Indy 等待这些客户端线程终止时会发生冻结,如果您的事件处理程序导致死锁(并且从 UI 线程之外访问 UI 组件可以死锁),它们将不会终止。
【参考方案1】:
您可能遇到过类似的问题:
Windows 2012 R2 closesocket() hangs on listening socket
该问题是由 Microsoft KB4338815 的补丁带来的,导致
closesocket
在 Intel Xeon 处理器上永远挂起
通过卸载您已安装的 KB4338815 解决了该问题。因此,请尝试在您的系统上卸载该 KB,看看它是否能解决您的问题。
【讨论】:
是的...在我们删除更新后一切正常。 在***.com/questions/51372116/… 中查看我的答案,了解微软的补丁以上是关于TIdHttpServer 在 Windows 更新后 Active 设置为 False 时冻结的主要内容,如果未能解决你的问题,请参考以下文章
IdHttpServer实现webservice(130篇DataSnap文章)
为啥在 Windows 上创建新进程比在 Linux 上更昂贵?